Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        private void ProcessSagaCommands(IMessageMetadata messageMetadata)
        {
            foreach (var cmd in Saga.CommandsToDispatch)
            {
                var metadata = messageMetadata.CreateChild(cmd.Id,
                                                           _sagaProducedEntry);

                Publisher.Publish(cmd, metadata);
            }

            Saga.ClearCommandsToDispatch();
        }
Пример #6
0
        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);
        }
Пример #7
0
        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));
            }
        }
Пример #9
0
 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);
     }
 }
Пример #10
0
 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);
     }
 }
Пример #11
0
        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);
        }
Пример #13
0
        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);
        }
Пример #14
0
        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;
                    }
                }
            }));
        }
Пример #15
0
        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());
        }
Пример #16
0
 public static MessageMetadata CreateChild(this IMessageMetadata metadata,
                                           IHaveId message,
                                           params ProcessEntry[] process)
 {
     return(metadata.CreateChild(message.Id, process));
 }
Пример #17
0
        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);
        }