public override async Task Invoke(IInvokeHandlerContext context, Func <Task> next) { if (!(context.MessageHandler.Instance is Saga)) { // Message was not handled by the saga await next().ConfigureAwait(false); return; } var logger = context.Logger(); if (!logger.IsEnabled(LogEventLevel.Information)) { await next().ConfigureAwait(false); return; } sagaAudit = new SagaUpdatedMessage { StartTime = DateTimeOffset.UtcNow }; context.Extensions.Set(sagaAudit); await next() .ConfigureAwait(false); if (context.Extensions.TryGet(out ActiveSagaInstance activeSagaInstance)) { sagaAudit.SagaType = activeSagaInstance.Instance.GetType().FullName; sagaAudit.FinishTime = DateTimeOffset.UtcNow; AuditSaga(activeSagaInstance, context); } }
public void Invoke(IncomingContext context, Action next) { var saga = context.MessageHandler.Instance as Saga; if (saga == null) { next(); return; } sagaAudit = new SagaUpdatedMessage { StartTime = DateTime.UtcNow }; context.Set(sagaAudit); next(); if (saga.Entity == null) { return; // Message was not handled by the saga } sagaAudit.FinishTime = DateTime.UtcNow; AuditSaga(saga, context); }
void AssignSagaStateChangeCausedByMessage(IInvokeHandlerContext context, SagaUpdatedMessage sagaAudit) { if (!context.Headers.TryGetValue("NServiceBus.Serilog.SagaStateChange", out var sagaStateChange)) { sagaStateChange = string.Empty; } var stateChange = "Updated"; if (sagaAudit.IsNew) { stateChange = "New"; } if (sagaAudit.IsCompleted) { stateChange = "Completed"; } if (!string.IsNullOrEmpty(sagaStateChange)) { sagaStateChange += ";"; } sagaStateChange += $"{sagaAudit.SagaId}:{stateChange}"; context.Headers["NServiceBus.Serilog.SagaStateChange"] = sagaStateChange; }
public static SagaSnapshot Create(SagaUpdatedMessage message) { var sagaSnapshot = new SagaSnapshot { SagaId = message.SagaId, SagaType = message.SagaType, FinishTime = message.FinishTime, StartTime = message.StartTime, StateAfterChange = message.SagaState, Endpoint = message.Endpoint, InitiatingMessage = CreateInitiatingMessage(message.Initiator) }; if (message.IsNew) { sagaSnapshot.Status = SagaStateChangeStatus.New; } else { sagaSnapshot.Status = SagaStateChangeStatus.Updated; } if (message.IsCompleted) { sagaSnapshot.Status = SagaStateChangeStatus.Completed; } sagaSnapshot.ProcessedAt = message.FinishTime; AddResultingMessages(message.ResultingMessages, sagaSnapshot); return sagaSnapshot; }
public override async Task Invoke(IInvokeHandlerContext context, Func <Task> next) { var sagaAudit = new SagaUpdatedMessage(); context.Extensions.Set(sagaAudit); await next().ConfigureAwait(false); if (!context.Extensions.TryGet(out ActiveSagaInstance activeSagaInstance)) { return; // Message was not handled by the saga } if (activeSagaInstance.Instance.Entity == null) { return; // Message was not handled by the saga } await AuditSaga(activeSagaInstance, sagaAudit, context).ConfigureAwait(false); }
public void SagaUpdated_serializes_correctly() { var entity = new SagaUpdatedMessage { SagaId = Guid.Empty, SagaState = "SagaState", Endpoint = "Endpoint", FinishTime = new DateTime(2017, 10, 30, 9, 22, 17, DateTimeKind.Utc), Initiator = new SagaChangeInitiator { InitiatingMessageId = "InitiatingMessageId", Intent = "intent", IsSagaTimeoutMessage = true, MessageType = "MessageType", OriginatingEndpoint = "OriginatingEndpoint", OriginatingMachine = "OriginatingMachine", TimeSent = new DateTime(2017, 10, 30, 9, 22, 17, DateTimeKind.Utc) }, IsCompleted = true, IsNew = true, ResultingMessages = { new SagaChangeOutput { Destination = "Destination", MessageType = "MessageType", DeliveryAt = new DateTime(2017, 10, 30, 9, 22, 17, DateTimeKind.Utc), DeliveryDelay = TimeSpan.FromSeconds(4000), Intent = "Intent", ResultingMessageId = "ResultingMessageId", TimeSent = new DateTime(2017, 10, 30, 9, 22, 17, DateTimeKind.Utc) } }, SagaType = "SagaType", StartTime = new DateTime(2017, 10, 30, 9, 22, 17, DateTimeKind.Utc) }; var serialized = SimpleJson.SimpleJson.SerializeObject(entity, new MessageSerializationStrategy()); Approver.Verify(serialized); }
Task AuditSaga(ActiveSagaInstance activeSagaInstance, SagaUpdatedMessage sagaAudit, IInvokeHandlerContext context) { if (!context.Headers.TryGetValue(Headers.MessageId, out var messageId)) { return(Task.FromResult(0)); } var saga = activeSagaInstance.Instance; string sagaStateString; if (customSagaEntitySerialization != null) { sagaStateString = SimpleJson.SerializeObject(customSagaEntitySerialization(saga.Entity)); } else { sagaStateString = SimpleJson.SerializeObject(saga.Entity, sagaEntitySerializationStrategy); } var messageType = context.MessageMetadata.MessageType.FullName; var headers = context.MessageHeaders; sagaAudit.StartTime = activeSagaInstance.Created.UtcDateTime; sagaAudit.FinishTime = activeSagaInstance.Modified.UtcDateTime; sagaAudit.Initiator = BuildSagaChangeInitiatorMessage(headers, messageId, messageType); sagaAudit.IsNew = activeSagaInstance.IsNew; sagaAudit.IsCompleted = saga.Completed; sagaAudit.Endpoint = endpointName; sagaAudit.SagaId = saga.Entity.Id; sagaAudit.SagaType = saga.GetType().FullName; sagaAudit.SagaState = sagaStateString; AssignSagaStateChangeCausedByMessage(context, activeSagaInstance, sagaAudit); var transportTransaction = context.Extensions.Get <TransportTransaction>(); return(backend.Send(sagaAudit, transportTransaction, context.CancellationToken)); }
public Task Send(SagaUpdatedMessage messageToSend, TransportTransaction transportTransaction, CancellationToken cancellationToken = default) { return(Send(messageToSend, TimeSpan.MaxValue, transportTransaction, cancellationToken)); }
static void AssignSagaStateChangeCausedByMessage(IInvokeHandlerContext context, ActiveSagaInstance sagaInstance, SagaUpdatedMessage sagaAudit) { if (!context.MessageHeaders.TryGetValue(SagaAuditHeaders.SagaStateChange, out var sagaStateChange)) { sagaStateChange = string.Empty; } var statechange = "Updated"; if (sagaInstance.IsNew) { statechange = "New"; } if (sagaInstance.Instance.Completed) { statechange = "Completed"; } if (!string.IsNullOrEmpty(sagaStateChange)) { sagaStateChange += ";"; } sagaStateChange += $"{sagaAudit.SagaId}:{statechange}"; context.Headers[SagaAuditHeaders.SagaStateChange] = sagaStateChange; }
public override async Task Invoke(IInvokeHandlerContext context, Func <Task> next) { if (context.MessageHandler.Instance is not Saga) { // Message was not handled by the saga await next(); return; } var logger = context.Logger(); if (!logger.IsEnabled(LogEventLevel.Information)) { await next(); return; } var sagaAudit = new SagaUpdatedMessage(); context.Extensions.Set(sagaAudit); var startTime = DateTimeOffset.UtcNow; await next(); var finishTime = DateTimeOffset.UtcNow; if (!context.Extensions.TryGet(out ActiveSagaInstance activeSagaInstance)) { return; } var saga = activeSagaInstance.Instance; if (saga.Entity is null) { //this can happen if it is a timeout or for invoking "saga not found" logic return; } var headers = context.Headers; if (!headers.TryGetValue(Headers.MessageId, out var messageId)) { return; } var isNew = activeSagaInstance.IsNew; var isCompleted = saga.Completed; var sagaId = saga.Entity.Id; AssignSagaStateChangeCausedByMessage(context, isNew, isCompleted, sagaId); var properties = new List <LogEventProperty> { new("SagaType", new ScalarValue(saga.GetType().Name)), new("SagaId", new ScalarValue(sagaId)), new("StartTime", new ScalarValue(startTime)), new("FinishTime", new ScalarValue(finishTime)), new("IsCompleted", new ScalarValue(isCompleted)), new("IsNew", new ScalarValue(isNew)) }; AddInitiator(context, messageId, properties); AddResultingMessages(sagaAudit, logger, properties); AddEntity(logger, saga, properties); logger.WriteInfo(messageTemplate, properties); }
void AuditSaga(ActiveSagaInstance activeSagaInstance, IInvokeHandlerContext context, SagaUpdatedMessage sagaAudit) { var saga = activeSagaInstance.Instance; if (saga.Entity == null) { //this can happen if it is a timeout or for invoking "saga not found" logic return; } var headers = context.Headers; if (!headers.TryGetValue(Headers.MessageId, out var messageId)) { return; } var intent = context.MessageIntent(); var initiator = new SagaChangeInitiator ( isSagaTimeoutMessage: context.IsTimeoutMessage(), initiatingMessageId: messageId, originatingMachine: context.OriginatingMachine(), originatingEndpoint: context.OriginatingEndpoint(), messageType: context.MessageType(), timeSent: context.TimeSent(), intent: intent ); sagaAudit.IsNew = activeSagaInstance.IsNew; sagaAudit.IsCompleted = saga.Completed; sagaAudit.SagaId = saga.Entity.Id; AssignSagaStateChangeCausedByMessage(context, sagaAudit); var properties = new List <LogEventProperty> { new LogEventProperty("SagaType", new ScalarValue(sagaAudit.SagaType)), new LogEventProperty("SagaId", new ScalarValue(sagaAudit.SagaId)), new LogEventProperty("StartTime", new ScalarValue(sagaAudit.StartTime)), new LogEventProperty("FinishTime", new ScalarValue(sagaAudit.FinishTime)), new LogEventProperty("IsCompleted", new ScalarValue(sagaAudit.IsCompleted)), new LogEventProperty("IsNew", new ScalarValue(sagaAudit.IsNew)), new LogEventProperty("SagaType", new ScalarValue(sagaAudit.SagaType)), }; var logger = context.Logger(); if (logger.BindProperty("Initiator", initiator, out var initiatorProperty)) { properties.Add(initiatorProperty); } if (logger.BindProperty("ResultingMessages", sagaAudit.ResultingMessages, out var resultingMessagesProperty)) { properties.Add(resultingMessagesProperty); } if (logger.BindProperty("Entity", saga.Entity, out var sagaEntityProperty)) { properties.Add(sagaEntityProperty); } logger.WriteInfo(messageTemplate, properties); }
void AuditSaga(ActiveSagaInstance activeSagaInstance, IInvokeHandlerContext context, SagaUpdatedMessage sagaAudit) { var saga = activeSagaInstance.Instance; if (saga.Entity == null) { //this can happen if it is a timeout or for invoking "saga not found" logic return; } var headers = context.Headers; if (!headers.TryGetValue(Headers.MessageId, out var messageId)) { return; } var intent = context.MessageIntent(); sagaAudit.IsNew = activeSagaInstance.IsNew; sagaAudit.IsCompleted = saga.Completed; sagaAudit.SagaId = saga.Entity.Id; AssignSagaStateChangeCausedByMessage(context, sagaAudit); List <LogEventProperty> properties = new() { new("SagaType", new ScalarValue(sagaAudit.SagaType)), new("SagaId", new ScalarValue(sagaAudit.SagaId)), new("StartTime", new ScalarValue(sagaAudit.StartTime)), new("FinishTime", new ScalarValue(sagaAudit.FinishTime)), new("IsCompleted", new ScalarValue(sagaAudit.IsCompleted)), new("IsNew", new ScalarValue(sagaAudit.IsNew)) }; var logger = context.Logger(); var messageType = TypeNameConverter.GetName(context.MessageType()); Dictionary <ScalarValue, LogEventPropertyValue> initiator = new() { { new("IsSagaTimeout"), new ScalarValue(context.IsTimeoutMessage()) }, { new("MessageId"), new ScalarValue(messageId) },