等待地铁传奇完成

时间:2019-03-04 22:24:59

标签: c# masstransit request-response

我正在尝试创建一个传奇,将一些结果返回给调用者,就像请求/响应模式一样。如果我调用Send方法,就可以启动传奇,但不能通过提交请求来实现。

因此,传奇逻辑运行良好,但不会向客户端返回任何内容。

或者提交请求后,它的使用者将对其进行处理,并将响应返回给客户端,但永远不会启动传奇。

更新masstransit deferred respond in sagas的答案似乎不适用于我的问题,原因有两个:

1)我无法通过调用Request方法来启动传奇;

2)如果我调用Send方法发送请求,然后再发送响应,则调用者线程在继续下一行代码之前不会等待响应返回;

[更新结束]

请找到完整的代码here。以下是更相关的片段:

这是传奇课:

public class MySaga : MassTransitStateMachine<MySagaState>
    {
        public static Uri address = new Uri($"loopback://localhost/req_resp_saga");

        public Event<IStartSagaCommand> StartSaga { get; private set; }

        public Request<MySagaState, MyRequest, MyResponse> SomeRequest { get; private set; }

        public MySaga()
        {
            InstanceState(s => s.CurrentState);

            Event(() => StartSaga,
                cc =>
                    cc.CorrelateBy(state => state.Data, context => context.Message.Data)
                        .SelectId(context => Guid.NewGuid()));

            Request(() => SomeRequest, x => x.NullableCorrelationId, cfg =>
            {
                cfg.ServiceAddress = address;
                cfg.SchedulingServiceAddress = address;
                cfg.Timeout = TimeSpan.FromSeconds(30);
            });

            Initially(
                When(StartSaga)
                    .Then(context =>
                    {
                        context.Instance.Data = context.Data.Data;
                    })
                    .ThenAsync(
                        context => Console.Out.WriteLineAsync($"Saga started: " +
                                                              $" {context.Data.Data} received"))
                    .Request(SomeRequest, context => new MyRequest() { CorrelationId = context.Instance.CorrelationId, RequestMessage = "Please do this" })
                    .TransitionTo(SomeRequest.Pending)
                    .ThenAsync(context => Console.Out.WriteLineAsync($"Transition completed: " +
                                                                     $" {(context.Instance.CurrentState == SomeRequest.Pending ? "pending" : "done")} received"))
                    //.Then(context =>
                    //{
                    //    var endpoint = context.GetSendEndpoint(address).GetAwaiter().GetResult();
                    //    endpoint.Send(new MyResponse() { CorrelationId = context.Instance.CorrelationId, ResponseMessage = "Your wish is my command" });
                    //})
            );

            During(SomeRequest.Pending,
                When(SomeRequest.Completed)
                    .ThenAsync(
                        context => Console.Out.WriteLineAsync($"Saga ended: " +
                                                              $" {context.Data.ResponseMessage} received"))
                    .Finalize()
            );
        }
    }

这开始了传奇故事,但不等待它完成并响应:

            var address = new Uri($"loopback://localhost/req_resp_saga");
            var endPoint = bus.GetSendEndpoint(address)
                .Result;

            endPoint.Send<IStartSagaCommand>(new { Data = "Hello World!!" });

这等待响应,但根本不涉及传奇:

var address = new Uri($"loopback://localhost/req_resp_saga");
            var requestClient = new MessageRequestClient<MyRequest, MyResponse>(bus, address, TimeSpan.FromSeconds(30));
            var response = requestClient.Request(new MyRequest() { CorrelationId = Guid.NewGuid(), RequestMessage = "Please do this" })
                .GetAwaiter()
                .GetResult();

我如何让呼叫者启动传奇,然后等待传奇结束并对其响应进行某些操作?

1 个答案:

答案 0 :(得分:0)

我自己就能找到解决方案。

问题是我对如何通过Request调用触发传奇感到困惑。我以为我必须声明

Request<in TInstance, TRequest, TResponse>

(自动)

那对我不起作用。

我用来开始传奇的事件有它自己的界面

Event<IStartSaga>

与我调用Request方法时使用的不同

var requestClient = new MessageRequestClient<MyRequest, MyResponse>(bus, address, TimeSpan.FromSeconds(30));
            var response = requestClient.Request(new MyRequest() { CorrelationId = Guid.NewGuid(), RequestMessage = "Please do this" })
                .GetAwaiter()
                .GetResult();

因此解决方法是将事件的声明更改为

Event<MyRequest>

现在,每当我通过My​​Resquest消息调用Request时,传奇便会开始。然后呼叫者等待传奇的响应。

我进行了一些其他更改以稍微清理代码并将其也推送到github。