【问题标题】:MassTransit 2.6.1 Request/Response pattern - Response times outMassTransit 2.6.1 请求/响应模式 - 响应超时
【发布时间】:2012-08-11 23:14:26
【问题描述】:

我正在将 MassTransit 视为要在 Web 项目中使用的 ServiceBus 实现。

我正在使用Request/Response 模式,发现消费者接收消息和响应与请求发布者处理响应之间存在很长的延迟;有时,似乎响应永远不会通过(让它运行了 10 分钟,响应仍然没有通过)。我看到句柄委托被调用并响应的唯一时间是在 30 秒超时时间之后并抛出超时异常;在这种情况下,处理程序委托上设置的断点被命中。

设置是标准事务 - 我有一个发布请求的 Web 应用程序,一个消费请求和发送响应的控制台应用程序,供 Web 应用程序处理回调中的响应。

我用的是Castle Windsor,容器是在web项目中使用WebActivator初始化的:

[assembly: WebActivator.PreApplicationStartMethod(typeof(BootStrapper), "PreStart")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(BootStrapper), "PostStart")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(BootStrapper), "Stop")]

namespace Web.App_Start
{
    public static class BootStrapper
    {
        internal static IWindsorContainer Container { get; private set; }

        public static void PreStart()
        {
            Container = new WindsorContainer().Install(FromAssembly.This());
        }

        public static void PostStart()
        {
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            ApiConfig.Configure(Container);
            MvcConfig.Configure(Container);
        }

        public static void Stop()
        {
            if (Container != null)
                Container.Dispose();
        }
    }
}

在网络应用项目(一个 ASP.NET Web API 项目)中,MassTransit 的 WindsorInstaller 看起来像

public class MassTransitInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(AllTypes.FromThisAssembly().BasedOn<IConsumer>());

        var bus = ServiceBusFactory.New(configurator =>
        {
            configurator.UseMsmq();
            configurator.VerifyMsmqConfiguration();            
            configurator.UseMulticastSubscriptionClient();

            configurator.ReceiveFrom("msmq://localhost/web");

            configurator.EnableMessageTracing();
            configurator.Subscribe(x => x.LoadFrom(container));
        });

        container.Register(Component.For<IServiceBus>().Instance(bus));
    }
}

在控制台应用程序项目中,WindsorInstaller 看起来像

public class MassTransitInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(AllTypes.FromAssemblyContaining<BasicRequestCommandHandler>().BasedOn<IConsumer>());

        var bus = ServiceBusFactory.New(configurator =>
        {
            configurator.UseMsmq();
            configurator.VerifyMsmqConfiguration();
            configurator.UseMulticastSubscriptionClient();

            configurator.ReceiveFrom("msmq://localhost/console");

            configurator.Subscribe(x => x.LoadFrom(container));
        });

        container.Register(Component.For<IServiceBus>().Instance(bus));
    }
}

我有一个ApiController,带有以下 GET 操作方法

public class ExampleController : ApiController
{
    private readonly IServiceBus _bus;

    public HelloController(IServiceBus bus)
    {
        _bus = bus;
    }

    // GET api/hello?text={some text}
    public Task<IBasicResponseCommand> Get(string text)
    {
        var command = new BasicRequestCommand {Text = text};

        var tcs = new TaskCompletionSource<IBasicResponseCommand>();

        _bus.PublishRequest(command, c =>
        {
            c.Handle<IBasicResponseCommand>(r =>
            {
                tcs.SetResult(r);
            });
        });

        return tcs.Task;
    }
}

BasicRequestCommand 和 BasicResponseCommand 看起来像这样

public interface IBasicRequestCommand
{
    Guid CorrelationId { get; set; }
    string Text { get; set; }
}

public class BasicRequestCommand :
    CorrelatedBy<Guid>, IBasicRequestCommand
{
    public Guid CorrelationId { get; set; }
    public string Text { get; set; }

    public BasicRequestCommand()
    {
        CorrelationId = Guid.NewGuid();
    }
}

public interface IBasicResponseCommand
{
    Guid CorrelationId { get; set; }
    string Text { get; set; }
}

public class BasicResponseCommand :
    CorrelatedBy<Guid>, IBasicResponseCommand
{
    public Guid CorrelationId { get; set; }
    public string Text { get; set; }
}

以及响应控制台应用程序中的 BasicRequestCommand 的处理程序:

public class BasicRequestCommandHandler : Consumes<IBasicRequestCommand>.Context
{
    public void Consume(IConsumeContext<IBasicRequestCommand> context)
    {
        Console.Out.WriteLine("received message text " + context.Message.Text);

        context.Respond(new BasicResponseCommand { Text = "Hello " + context.Message.Text, CorrelationId = context.Message.CorrelationId });
    }
}

我预计所有这些都在本地运行,请求/响应最多大约几秒钟。我在配置中遗漏了什么吗?

此外,我想将 MassTransit 连接到 log4net。我正在使用 Windsor 的 log4net 日志记录工具,并且在 web.config 中有一个 log4net 部分。这对于 Windsor 提供的 ILogger 实现(以及 NHibernate 日志记录)都可以正常工作,但它是 not clear from the documentation how to configure MassTransit to use this for logging。有什么想法吗?

【问题讨论】:

    标签: castle-windsor log4net msmq masstransit


    【解决方案1】:

    在 2.6.2 版本中修复了 ASP.NET 中请求/响应的响应超时问题。 https://groups.google.com/d/topic/masstransit-discuss/oC1FOe6KsAU/discussion

    【讨论】:

      【解决方案2】:

      正如安德烈沃尔科夫和克里斯帕特森 were discussing 在 MassTransit 谷歌小组中一样,这个问题似乎源于 switching MassTransit 到使用 SynchronizationContext,由于某种原因不能按预期工作。

      目前一种解决方法似乎是转换到异步 MassTransit 请求,或者返回到不使用违规 SynchronizationContext 的 v2.1.1。

      (如果没有其他人首先这样做,将在此处发布有关此问题的更新以供后代使用。)

      【讨论】:

      • 谢谢戴夫。通读该线程,这正是我所看到的行为。我暂时可以解决它,但很高兴了解幕后发生的事情。
      • Chris Patterson 已经确认,SynchronizationContext 的当前(从 v2.6.1 开始)实现需要更多的 TLC。昨晚的change was pushed to github 使使用上下文成为可选。目前它位于 develop 分支上,尚未正式推出,但您应该可以签出 master 分支,挑选我提到的更改去、建设和做好准备。
      • 回到2.6.3之前的行为,不再使用SynchronizationContext,因为调用线程可能被阻塞等待接收者。
      【解决方案3】:

      当您使用 MultiCastSubscriptionClient 时,您必须在每台机器上调用 SetNetwork(NETWORK_KEY)(对 NETWORK_KEY 使用相同的值)。此外,所有参与的机器都需要在同一个子网中 - 请参阅http://masstransit.readthedocs.org/en/latest/overview/subscriptions.html#msmq-multicast 的文档

      对于连接 log4net,这取决于您使用的版本,但在最新版本中,您包含 MassTransit.Log4NetIntegration 程序集,然后在您的服务总线配置中调用 cfg.UseLog4Net();

      如果您仍然卡住,您可以通过https://groups.google.com/forum/?fromgroups#!forum/masstransit-discuss 询问 MT 邮件列表

      【讨论】:

      • 即使 Web 和控制台应用程序都在同一台机器上运行,您是否必须调用 SetNetwork?
      • 我认为你不需要,不。
      • 谢谢。两个应用程序都在同一台机器上运行,所以我认为我不需要设置网络密钥。我会试试这个小组,因为我看不出任何直接原因导致它需要这么长时间或根本没有发生。
      • 控制器的 Get() 方法是否应该在其签名中没有“异步”......?
      • 不,asp.net web api 操作方法可以返回Task&lt;T&gt;。如果我没有使用TaskCompletionSource&lt;T&gt; 并且可以await 对已发布请求的响应,那么是的,方法签名将需要async 关键字。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 2012-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多