private async Task ProcessCommand(ICommand command, JobDataMap jobDataMap, IMessageMetadata metadata, JobKey jobKey) { var options = Get <ExecutionOptions>(jobDataMap, ExecutionOptionsKey); if (options.SuccesEventType == null) { throw new OptionsNotFilledException("options do not have SuccessEventType for key " + jobKey); } var commandMetadata = metadata.CreateChild(command.Id, new ProcessEntry(nameof(QuartzJob), PassingCommandToExecutor, CommandRaiseTime)); //waiting domain event by correlation id await _executor.Prepare(command, commandMetadata) .Expect(options.SuccesEventType) .Execute(options.Timeout, true); _quartzLogger.Information("job {key} succeed", jobKey.Name); var successMetadata = commandMetadata.CreateChild(Guid.NewGuid().ToString(), new ProcessEntry(nameof(QuartzJob), "Publishing success notification", "Job execution completed succesfully. Command executed and confirmed.")); var jobSucceeded = new JobSucceeded(jobKey.Name, jobKey.Group, command); _publisher.Publish(jobSucceeded, successMetadata); }
public void Handle(FutureEventScheduledEvent futureEventScheduledEvent, IMessageMetadata messageMetadata) { var message = futureEventScheduledEvent; Guid scheduleId = message.Id; Guid aggregateId = message.Event.SourceId; var description = $"Aggregate {typeof(TAggregate).Name} id = {aggregateId} scheduled future event " + $"{scheduleId} with payload type {message.Event.GetType().Name} on time {message.RaiseTime}\r\n" + $"Future event: {message.ToPropsString()}"; var scheduleKey = CreateScheduleKey(scheduleId, aggregateId, description); var command = new RaiseScheduledDomainEventCommand(message.Id, message.SourceId, Guid.NewGuid()); var metadata = messageMetadata.CreateChild(command.Id, new ProcessEntry(GetType().Name, "Scheduling raise future event command", "FutureEventScheduled event occured")); var confirmationEventType = typeof(IMessageMetadataEnvelop<>).MakeGenericType(message.Event.GetType()); var scheduleEvent = new ScheduleCommand(command, scheduleKey, new ExtendedExecutionOptions(message.RaiseTime, confirmationEventType, message.Event.SourceId, nameof(DomainEvent.SourceId)), metadata); _schedulerActorRef.Handle(scheduleEvent); }
private object[] ProcessSagaStateChange(IMessageMetadata mutatorMessageMetadata) { var stateChangeEvents = State.GetUncommittedEvents().Cast <DomainEvent>().ToArray(); int totalEvents = stateChangeEvents.Length; int persistedEvents = 0; PersistAll(stateChangeEvents, e => { var metadata = mutatorMessageMetadata.CreateChild(e.SourceId, new ProcessEntry(Self.Path.Name, "Saga state event published", "Saga changed state")); Publisher.Publish(e, metadata); NotifyWatchers(new Persisted(e)); //should save snapshot only after all messages persisted as state was already modified by all of them if (++persistedEvents == totalEvents) { TrySaveSnapshot(stateChangeEvents); } }); State.ClearUncommittedEvents(); return(stateChangeEvents); }
private void ProcessFault(ICommand cmd, Exception ex, IMessageMetadata messageMetadata) { var fault = Fault.NewGeneric(cmd, ex, typeof(TAggregate), cmd.SagaId); var metadata = messageMetadata.CreateChild(cmd.Id, new ProcessEntry(Self.Path.Name, CreatedFault, CommandRaisedAnError)); Publisher.Publish(fault, metadata); Log.Error(ex, "{Aggregate} raised an expection {@Exception} while executing {@Command}", State.Id, ex, cmd); }
private void ProcessSagaCommands(IMessageMetadata messageMetadata) { foreach (var cmd in Saga.CommandsToDispatch) { var metadata = messageMetadata.CreateChild(cmd.Id, _sagaProducedEntry); Publisher.Publish(cmd, metadata); } Saga.ClearCommandsToDispatch(); }
public void Handle(SampleAggregateChangedEvent msg, IMessageMetadata metadata) { var notificationMetadata = metadata.CreateChild(Guid.NewGuid(), new ProcessEntry(nameof(SampleProjectionBuilder), "Publishing notification", "Aggregate created event processed")); _publisher.Publish(new AggregateChangedEventNotification() { AggregateId = msg.SourceId }, notificationMetadata); }
protected virtual void PublishError(TMessage msg, IMessageMetadata metadata, Exception ex) { _log.Error(ex, "Handler actor raised an error on message process: {@msg}. Count: {count}", msg, ++_publishFaultCount); var faultMetadata = metadata.CreateChild(msg.Id, FaltProcessEntry); var fault = Fault.NewGeneric(msg, ex, msg.ProcessId, typeof(THandler)); Publisher.Publish(fault, faultMetadata); }
public async Task Handle(BalloonCreated msg, IMessageMetadata metadata = null) { _log.Debug("Projecting balloon catalog from message {@msg}", msg); using (var context = _contextCreator()) { context.BalloonCatalog.Add(msg.ToCatalogItem()); await context.SaveChangesAsync(); _publisher.Publish(new BalloonCreatedNotification() { BallonId = msg.SourceId }, metadata.CreateChild(Guid.NewGuid().ToString(), _readModelUpdatedProcessEntry)); } }
private async Task WithErrorHandling(IHaveId processingMessage, IMessageMetadata messageMetadata, JobKey key, Func <Task> act) { try { await act(); } catch (Exception e) { var businessError = e.UnwrapSingle(); _quartzLogger.Error(businessError, "job {key} failed", key.Name); var jobFailed = new JobFailed(key.Name, key.Group, businessError, processingMessage); var jobFailedMetadata = messageMetadata.CreateChild(processingMessage, _jobFailedProcessEntry); _publisher.Publish(jobFailed, jobFailedMetadata); throw new JobExecutionException(businessError, false); } }
private void WithErrorHandling(object processingMessage, IMessageMetadata messageMetadata, JobKey key, Action act) { try { act(); } catch (Exception e) { _quartzLogger.LogFailure(key.Name, e); var jobFailed = new JobFailed(key.Name, key.Group, e, processingMessage); var jobFailedMetadata = messageMetadata.CreateChild(Guid.Empty, new ProcessEntry(nameof(QuartzJob), PublishingJobFaulire, JobRaiseTimeCame)); _publisher.Publish(jobFailed, jobFailedMetadata); throw new JobExecutionException(e, false); } }
private void ProcessEvent(IMessageMetadata metadata, JobKey jobKey, DomainEvent messageToFire) { var eventMetadata = metadata.CreateChild(messageToFire.SourceId, new ProcessEntry(nameof(QuartzJob), PublishingEvent, EventRaiseTimeCame)); var successMetadata = eventMetadata.CreateChild(Guid.NewGuid(), new ProcessEntry(nameof(QuartzJob), "Publishing success notification", "Job execution completed succesfully. Message published.")); var jobSucceeded = new JobSucceeded(jobKey.Name, jobKey.Group, messageToFire); _publisher.Publish(messageToFire, eventMetadata); _publisher.Publish(jobSucceeded, successMetadata); }
public async Task Handle(BalloonTitleChanged msg, IMessageMetadata metadata = null) { _log.Debug("Projecting balloon catalog from message {@msg}", msg); using (var context = _contextCreator()) { var balloon = await context.BalloonCatalog.FindAsync(msg.SourceId); balloon.Title = msg.Value; balloon.TitleVersion++; context.BalloonCatalog.Update(balloon); await context.SaveChangesAsync(); _publisher.Publish(new BalloonTitleChangedNotification() { BallonId = msg.SourceId }, metadata.CreateChild(Guid.NewGuid().ToString(), _readModelUpdatedProcessEntry)); } _log.Debug("Projected balloon catalog from message {@msg}", msg); }
private void ProcessSaga(object message, IMessageMetadata messageMetadata) { try { Saga.Transit(message); } catch (Exception ex) { var processorType = _producer.Descriptor.StateMachineType; _log.Error(ex, "Saga {saga} {id} raised an error on {@message}", processorType, Id, message); var fault = Fault.NewGeneric(message, ex, processorType, Id); var metadata = messageMetadata.CreateChild(fault.SagaId, _exceptionOnTransit); Publisher.Publish(fault, metadata); return; } var stateChange = ProcessSagaStateChange(messageMetadata); ProcessSagaCommands(messageMetadata); }
public Task Handle(FutureEventScheduledEvent message, IMessageMetadata messageMetadata) { var scheduleId = message.Id; var succesEventType = message.Event.GetType(); var description = $"Source {message.SourceName} id={message.SourceId} scheduled future event {message.Event.GetType().Name} id={scheduleId} o n{message.RaiseTime}\r\n"; var scheduleKey = CreateScheduleKey(scheduleId, message.SourceId, message.SourceName, description); var command = new RaiseScheduledDomainEventCommand(message.Id, message.SourceId, Guid.NewGuid().ToString()); var metadata = messageMetadata.CreateChild(command.Id, _schedulingFutureEventProcessEntry); var scheduleEvent = new ScheduleCommandExecution(command, scheduleKey, ExecutionOptions.ForCommand(message.RaiseTime, succesEventType), metadata); return(_schedulerActorRef.Ask <object>(scheduleEvent).ContinueWith(t => { switch (t.Result) { case CommandExecutionScheduled sched: break; case Failure f: { _logger.Error(f.Exception, "Error occured during scheduling event"); break; } default: { _logger.Error("Unexpected message received during scheduling event confirmation wait: {msg}", t.Result); break; } } })); }
private void ProcessAggregateEvents(ICommand command, IMessageMetadata metadata) { var events = ExecuteCommand(command); int totalEvents = events.Length; int persistedEvents = 0; PersistAll(events, e => { var eventMetadata = metadata.CreateChild(e.SourceId, new ProcessEntry(Self.Path.Name, PublishingEvent, CommandExecutionCreatedAnEvent)); //TODO: move scheduling event processing to some separate handler or aggregateActor extension. //how to pass aggregate type in this case? //direct call to method to not postpone process of event scheduling, //case it can be interrupted by other messages in stash processing errors e.Match().With<FutureEventScheduledEvent>(m => Handle(m, eventMetadata)) .With<FutureEventCanceledEvent>(m => Handle(m, eventMetadata)); Publisher.Publish(e, eventMetadata); //should save snapshot only after all messages persisted as state was already modified by all of them if(++persistedEvents == totalEvents) TrySaveSnapshot(events); NotifyWatchers(new Persisted(e)); }); State.ClearUncommittedEvents(); ProcessAsyncMethods(command, metadata); if(SnapshotsPolicy.ShouldSave(events)) SaveSnapshot(State.GetSnapshot()); }
public static MessageMetadata CreateChild(this IMessageMetadata metadata, IHaveId message, params ProcessEntry[] process) { return(metadata.CreateChild(message.Id, process)); }
private void ProcessCommand(ICommand command, JobDataMap jobDataMap, IMessageMetadata metadata, JobKey jobKey) { var key = GetScheduleKey(jobDataMap); var options = GetExecutionOptions(jobDataMap, jobKey.Name); if (options.SuccesEventType == null) { throw new Exception("options do not have SuccessEventType for key " + key); } Predicate <object> isExpected = (o => true); //we should work with legacy jobs having only ExecutionOptions, not ExtendedExecutionOptions var extendedOptions = options as ExtendedExecutionOptions; if (!string.IsNullOrEmpty(extendedOptions?.MessageIdFieldName)) { isExpected = o => { var envelop = o as IMessageMetadataEnvelop; if (envelop != null) { o = envelop.Message; } //received fault instead of expected message var type = o?.GetType(); var guid = type?.GetProperty(extendedOptions.MessageIdFieldName)? .GetValue(o); return(guid != null && (Guid)guid == extendedOptions.SuccessMessageId); }; } var commandMetadata = metadata.CreateChild(command.Id, new ProcessEntry(nameof(QuartzJob), PassingCommandToExecutor, CommandRaiseTimeCame)); var task = _executor.NewCommandWaiter(options.Timeout) .Expect(options.SuccesEventType, o => isExpected(o)) .Create() .Execute(command, commandMetadata); if (!task.Wait(options.Timeout)) { throw new ScheduledCommandWasNotConfirmedException(command); } _quartzLogger.LogSuccess(jobKey.Name); var successMetadata = commandMetadata.CreateChild(Guid.NewGuid(), new ProcessEntry(nameof(QuartzJob), "Publishing success notification", "Job execution completed succesfully. Command executed and confirmed.")); var jobSucceeded = new JobSucceeded(jobKey.Name, jobKey.Group, command); _publisher.Publish(jobSucceeded, successMetadata); }