我有一个非常简单的调度程序传奇,它应该每天发送一个特定的消息。它被实现为请求超时的传奇。当处理超时时,执行一个动作(发送一条消息),并在第二天请求新的超时。
我在成功之前做了完全相同的事情,但现在超时似乎立即触发,所以请求DateTime。
端点是自托管的,并配置为使用InMemoryPersistence。 NServiceBus版本是6.4.3。
传奇的实施如下。我已经删除了所有逻辑,但仍会立即无限地收到超时消息。
public class SchedulerSaga: Saga<SchedulerState>,
IAmStartedByMessages<StartSchedulerSagaCommand>,
IHandleTimeouts<SchedulerTimeout>
{
private readonly IConfigurationProvider _config;
public SchedulerSaga(IConfigurationProvider config)
{
_config = config;
}
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<SchedulerState> mapper)
{
mapper.ConfigureMapping<StartSchedulerSagaCommand>(_ => _.SchedulerName).ToSaga(_ => _.SchedulerName);
}
public async Task Handle(StartSchedulerSagaCommand message, IMessageHandlerContext context)
{
Data.SchedulerName = message.SchedulerName;
await StartProcessAndScheduleNewTimeout(context);
}
public async Task Timeout(SchedulerTimeout state, IMessageHandlerContext context)
{
Data.Counter++;
await StartProcessAndScheduleNewTimeout(context);
}
private async Task StartProcessAndScheduleNewTimeout(IMessageHandlerContext context)
{
await RequestTimeout(context, new DateTime(2018, 9, 16, 0, 0, 0, DateTimeKind.Utc), new SchedulerTimeout { Counter = Data.Counter });
}
}
端点配置如下:
public static EndpointConfiguration ConfigureMsmqEndpoint(IWindsorContainer container)
{
var endpointConfiguration = new EndpointConfiguration(MsmqEndpointName);
ConfigureRouting(endpointConfiguration);
endpointConfiguration.UsePersistence<InMemoryPersistence>();
endpointConfiguration.SendFailedMessagesTo($"{MsmqEndpointName}.error");
endpointConfiguration.AssemblyScanner().ExcludeAssemblies("tools");
endpointConfiguration.EnableInstallers();
ConfigureUnobtrusiveMessageConvention(endpointConfiguration);
endpointConfiguration.Recoverability().Delayed(DelayedSettings);
endpointConfiguration.UseContainer<WindsorBuilder>(c => c.ExistingContainer(container));
return endpointConfiguration;
}
我也尝试使用内置的调度机制,同样的事情发生,每秒都会触发超时的数量。
await endpointInstance.ScheduleEvery(
timeSpan: TimeSpan.FromMinutes(5),
task: context=> context.SendLocal(new SomeMessage())
)
.ConfigureAwait(false);
更新:使用代码重现问题添加repo。
https://github.com/spinakr/nsb-scheduling-msmq
只有在项目中引用“NServiceBus.Azure.Transports.WindowsAzureStorageQueues”包时才会出现问题,即使它没有被使用!
正在审核的应用在同一进程中托管了两个端点。使用来自MSMQ和Azure存储队列的消息。在repo中,只有在添加azure存储队列传输包时才会发生问题。
答案 0 :(得分:2)
我假设你描述的端点正在使用MSMQ作为传输(基于方法和字段的名称),并且saga正在该端点上运行。
MSMQ依靠超时管理器来支持延迟交付。另一方面,Azure存储队列传输似乎以不同的方式解决延迟传递。它实际上有一个feature,默认情况下启用,可以防止延迟消息被路由到超时管理器。如果您的MSMQ端点要扫描 NServiceBus.Azure.Transports.WindowsAzureStorageQueues 程序集,则延迟消息将无法到达超时管理器。
此问题的一个解决方案是在MSMQ端点中配置程序集扫描程序以排除该程序集:
endpointConfiguration.AssemblyScanner().ExcludeAssemblies(
"NServiceBus.Azure.Transports.WindowsAzureStorageQueues.dll");
答案 1 :(得分:1)
在同一进程中共同托管多个端点时的另一个考虑因素 - 共享处理程序。您可能希望查看Endpoints multi hosting示例,其中提到了如何使用黑名单的程序集扫描来避免不需要的程序集加载。