dtm-labs/client-csharp

Support for GRPC Endpoints

c5racing opened this issue · 3 comments

All of our microservices are GRPC. I'm interested in using DTM from my aggregator to call multiple GRPC services and if one fails, use DTM to call the compensating transaction.

Can DTM be used to call GRPC endpoints or only REST? I don't see any examples of the GRPC.

@c5racing Thanks for your interest in DTM.

DTM support both GRPC endpoints and REST endpoint.

What kind of examples do you need?

In all of the DTM examples, calling a GRPC service appears to rely on calling a URL specifically, not using the C# service Client. See my vary simple example below, I am calling two GRPC Services using the Service Client, and comparing the result for my return value.

If I implement DTM, can I use the C# Service Client and how do I get access to the result of each GRPC call, assuming they both succeed? Further, can I use the result of the first call, in the second call and then compensate them both in one or both fail?

using Application.Shared.GrpcExtensions;
using Dtmgrpc;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using ProtocolBuffers.Protos.Global.API;
using static ProtocolBuffers.Protos.Global.API.CountryGrpcService;
using static ProtocolBuffers.Protos.Global.API.CountyGrpcService;

namespace Console.Web.Application.Configuration;

public class TestService(CountryGrpcServiceClient countryGrpcServiceClient, CountyGrpcServiceClient countyGrpcServiceClient, IDtmgRPCClient dtmClient, IDtmTransFactory transFactory)
{
    private readonly Metadata _headers;

    public async Task<bool> UpdateMultipleEndpoints(Empty request, ServerCallContext context)
    {
        var countryRequest = new UpdateCountryRequest();
        var countyRequest = new UpdateCountyRequest();

        //Sample Code
        var countryTask = countryGrpcServiceClient.UpdateAsync(countryRequest, new CallOptions(deadline: GrpcMethods.GetDeadline(context.Deadline), headers: _headers, cancellationToken: context.CancellationToken)).ResponseAsync;
        var countyTask = countyGrpcServiceClient.UpdateAsync(countyRequest, new CallOptions(deadline: GrpcMethods.GetDeadline(context.Deadline), headers: _headers, cancellationToken: context.CancellationToken)).ResponseAsync;
        await Task.WhenAll(countryTask, countyTask);

        var country = await countryTask;
        var county = await countyTask;

        //return county == country;
        
        //End Sample Code

        //Replace with DTM Here
        string gid = await dtmClient.GenGid();

        //How to I use ServiceClient?

        var saga = transFactory.NewSagaGrpc(gid)
            .Add("UpdateCountry", "CompensateCountry", countyRequest)
            .Add("UpdateCounty", "CompensateCounty", countyRequest);

        await saga.Submit();

        //How do I look at the results of each GRPC Call?

        //Replace with DTM Here
    }
}

For SAGA, you can take a look on the following sample.

private SagaGrpc GenSagaGrpc(IDtmTransFactory transFactory, string gid, bool outFailed, bool inFailed)
{
var saga = transFactory.NewSagaGrpc(gid);
var req = ITTestHelper.GenBusiReq(outFailed, inFailed);
var busiGrpc = ITTestHelper.BuisgRPCUrl;
saga.Add(busiGrpc + "/busi.Busi/TransOut", busiGrpc + "/busi.Busi/TransOutRevert", req);
saga.Add(busiGrpc + "/busi.Busi/TransIn", busiGrpc + "/busi.Busi/TransInRevert", req);
return saga;
}

If I implement DTM, can I use the C# Service Client and how do I get access to the result of each GRPC call, assuming they both succeed?

You do not need to use C# Service Client, and the DTM server will tell you if the transaction was successful.

Take a look on the following link.
https://en.dtm.pub/practice/saga.html

//How do I look at the results of each GRPC Call?

Take a look on the log of DTM server.