来自文档here:
如果端点的配置发生变化,或者是否有消息 错误地发送到端点,可能是消息类型 收到的没有任何连接的消费者。如果发生这种情况 邮件被移动到_skipped队列(前缀为原始队列) 队列名称)。原始邮件内容将保留,另外还有 添加标头以指示移动消息的主机。
当一些消息试图传递给saga但是saga实例还没有创建时,我是否应该期待一个saga的相同行为? 换句话说,如果想要在传奇中处理消息,但该消息不是传奇创建的触发器。我希望在_skipped队列中看到这些消息,但实际上我没有在_skipped或_error队列中看到它们。此外,我可以看到按摩成功传递到传奇队列,并成功地以某种方式消耗没有任何警告或错误。谁消费了这条消息?
已更新
状态机:
public class TestState : SagaStateMachineInstance, IVersionedSaga
{
public Guid CorrelationId { get; set; }
public Guid Id { get; set; }
public string CurrentState { get; set; }
public int Version { get; set; }
public DateTime TimeStart { get; set; }
public int Progress { get; set; }
}
public class TestStateMachine : MassTransitStateMachine<TestState>
{
public TestStateMachine()
{
InstanceState(x => x.CurrentState);
Event(() => ProcessingStarted, x => x.CorrelateById(context => context.Message.Id));
Event(() => ProgressUpdated, x => x.CorrelateById(context => context.Message.Id));
Event(() => ProcessingFinished, x => x.CorrelateById(context => context.Message.Id));
Initially(
When(ProcessingStarted)
.Then(context =>
{
context.Instance.TimeStart = DateTime.Now;
})
.TransitionTo(Processing)
);
During(Processing,
When(ProgressUpdated)
.Then(context =>
{
context.Instance.Progress = context.Data.Progress;
}),
When(ProcessingFinished)
.TransitionTo(Processed)
.ThenAsync(async context =>
{
await context.Raise(AllDone);
})
);
During(Processed,
When(AllDone)
.Then(context =>
{
Log.Information($"Saga {context.Instance.Id} finished");
})
.Finalize());
SetCompletedWhenFinalized();
}
public State Processing { get; set; }
public State Processed { get; set; }
public Event AllDone { get; set; }
public Event<ProcessingStarted> ProcessingStarted { get; set; }
public Event<ProgressUpdated> ProgressUpdated { get; set; }
public Event<ProcessingFinished> ProcessingFinished { get; set; }
}
public interface ProcessingStarted
{
Guid Id { get; }
}
public interface ProgressUpdated
{
Guid Id { get; }
int Progress { get; }
}
public interface ProcessingFinished
{
Guid Id { get; }
}
配置
var repository = new MongoDbSagaRepository<TestState>(Environment.ExpandEnvironmentVariables(configuration["MongoDb:ConnectionString"]), "sagas");
var services = new ServiceCollection();
services.AddSingleton(context => Bus.Factory.CreateUsingRabbitMq(x =>
{
IRabbitMqHost host = x.Host(new Uri(Environment.ExpandEnvironmentVariables(configuration["MassTransit:ConnectionString"])), h => { });
x.ReceiveEndpoint(host, "receiver_saga_queue", e =>
{
e.StateMachineSaga(new TestStateMachine(), repository);
});
x.UseRetry(r =>
{
r.Incremental(10, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(50));
r.Handle<MongoDbConcurrencyException>();
r.Handle<UnhandledEventException>();
});
x.UseSerilog();
}));
var container = services.BuildServiceProvider();
var busControl = container.GetRequiredService<IBusControl>();
busControl.Start();
稍后,当我发布ProgressUpdated
事件
busControl.Publish<ProgressUpdated>(new
{
Id = id,
Progress = 50
});
我希望它会引发UnhandledEventException
并将按摩移动到_error队列但实际上我可以看到该消息出现在队列中,以某种方式消耗,我在_error或_skipped队列中都看不到它。 MongoDB Saga存储也没有创建任何新的saga实例。
我做错了什么?我需要配置saga的方式是,如果在未创建saga实例时获得ProgressUpdated
事件,则稍后在实例准备好接受它时将重试它。
解
将事件ProgressUpdated
和ProcessingFinished
重新配置为
Event(() => ProgressUpdated, x =>
{
x.CorrelateById(context => context.Message.Id);
x.OnMissingInstance(m => m.Fault());
});
Event(() => ProcessingFinished, x =>
{
x.CorrelateById(context => context.Message.Id);
x.OnMissingInstance(m => m.Fault());
});
并稍后在SagaException
中抓取UseRetry
r.Handle<SagaException>();
完成了工作!
感谢@Alexey Zimarev分享知识!
答案 0 :(得分:1)
如果消息应由传奇处理,但没有匹配的实例,则会调用OnMissingInstance
回调。
重新配置ProgressUpdated
和ProcessingFinished
:
Event(() => ProgressUpdated, x =>
{
x.CorrelateById(context => context.Message.Id);
x.OnMissingInstance(m => m.Fault());
});
Event(() => ProcessingFinished, x =>
{
x.CorrelateById(context => context.Message.Id);
x.OnMissingInstance(m => m.Fault());
});
并在重试过滤器中捕获SagaException
:
r.Handle<SagaException>();