public JobServiceConfigurator(IServiceInstanceConfigurator <TReceiveEndpointConfigurator> instanceConfigurator)
        {
            _instanceConfigurator = instanceConfigurator;

            JobService = new JobService(_instanceConfigurator.InstanceAddress);

            instanceConfigurator.ConnectBusObserver(new JobServiceBusObserver(JobService));
            instanceConfigurator.AddSpecification(this);

            _options = _instanceConfigurator.Options <JobServiceOptions>(options =>
            {
                options.JobService = JobService;

                options.JobTypeSagaEndpointName    = _instanceConfigurator.EndpointNameFormatter.Saga <JobTypeSaga>();
                options.JobStateSagaEndpointName   = _instanceConfigurator.EndpointNameFormatter.Saga <JobSaga>();
                options.JobAttemptSagaEndpointName = _instanceConfigurator.EndpointNameFormatter.Saga <JobAttemptSaga>();
            });

            _instanceConfigurator.ConnectEndpointConfigurationObserver(new JobServiceEndpointConfigurationObserver(_options, cfg =>
            {
                if (_jobTypeSagaEndpointConfigurator != null)
                {
                    cfg.AddDependency(_jobTypeSagaEndpointConfigurator);
                }
                if (_jobSagaEndpointConfigurator != null)
                {
                    cfg.AddDependency(_jobSagaEndpointConfigurator);
                }
                if (_jobAttemptSagaEndpointConfigurator != null)
                {
                    cfg.AddDependency(_jobAttemptSagaEndpointConfigurator);
                }
            }));
        }
Example #2
0
 public JobServiceConsumerConfigurationObserver(IReceiveEndpointConfigurator configurator, JobServiceOptions jobServiceOptions,
                                                Action <IReceiveEndpointConfigurator> configureEndpoint)
 {
     _configurator      = configurator;
     _jobServiceOptions = jobServiceOptions;
     _configureEndpoint = configureEndpoint;
 }
Example #3
0
        public JobService(Uri instanceAddress, JobServiceOptions options)
        {
            _options        = options;
            InstanceAddress = instanceAddress;

            _jobTypes = new Dictionary <Type, IJobTypeRegistration>();
            _jobs     = new ConcurrentDictionary <Guid, JobHandle>();
        }
Example #4
0
        public JobServiceConsumerConfigurationObserver(IReceiveEndpointConfigurator configurator, JobServiceOptions jobServiceOptions,
                                                       Action <IReceiveEndpointConfigurator> configureEndpoint)
        {
            _configurator      = configurator;
            _jobServiceOptions = jobServiceOptions;
            _configureEndpoint = configureEndpoint;

            _consumerConfigurators = new Dictionary <Type, IConsumeConfigurator>();
        }
        /// <summary>
        /// Configures support for job consumers on the service instance, which supports executing long-running jobs without blocking the consumer pipeline.
        /// Job consumers use multiple state machines to track jobs, each of which runs on its own dedicated receive endpoint. Multiple service
        /// instances will use the competing consumer pattern, so a shared saga repository should be configured.
        /// This method does not configure the state machine endpoints required to use the job service, and should only be used for services where another
        /// service has the job service endpoints configured.
        /// </summary>
        /// <typeparam name="T">The transport receive endpoint configurator type</typeparam>
        /// <param name="configurator">The Conductor service instance</param>
        /// <param name="options"></param>
        /// <param name="configure"></param>
        internal static IServiceInstanceConfigurator <T> ConfigureJobService <T>(this IServiceInstanceConfigurator <T> configurator,
                                                                                 JobServiceOptions options, Action <IJobServiceConfigurator> configure = default)
            where T : IReceiveEndpointConfigurator
        {
            var jobServiceConfigurator = new JobServiceConfigurator <T>(configurator, options);

            configure?.Invoke(jobServiceConfigurator);

            return(configurator);
        }
        /// <summary>
        /// Configures support for job consumers on the service instance, which supports executing long-running jobs without blocking the consumer pipeline.
        /// Job consumers use multiple state machines to track jobs, each of which runs on its own dedicated receive endpoint. Multiple service
        /// instances will use the competing consumer pattern, so a shared saga repository should be configured.
        /// This method does not configure the state machine endpoints required to use the job service, and should only be used for services where another
        /// service has the job service endpoints configured.
        /// </summary>
        /// <typeparam name="T">The transport receive endpoint configurator type</typeparam>
        /// <param name="configurator">The Conductor service instance</param>
        /// <param name="options"></param>
        internal static IServiceInstanceConfigurator <T> ConfigureJobService <T>(this IServiceInstanceConfigurator <T> configurator,
                                                                                 JobServiceOptions options)
            where T : IReceiveEndpointConfigurator
        {
            var jobServiceConfigurator = new JobServiceConfigurator <T>(configurator);

            jobServiceConfigurator.ApplyJobServiceOptions(options);

            return(configurator);
        }
Example #7
0
        public JobService(IServiceInstanceConfigurator configurator, JobServiceOptions options)
        {
            _options        = options;
            InstanceAddress = configurator.InstanceAddress;

            _jobTypes = new Dictionary <Type, IJobTypeRegistration>();
            _jobs     = new ConcurrentDictionary <Guid, JobHandle>();

            ConfigureSuperviseJobConsumer(configurator.InstanceEndpointConfigurator);
        }
        public JobTypeStateMachine(JobServiceOptions options)
        {
            Event(() => JobSlotRequested, x =>
            {
                x.CorrelateById(m => m.Message.JobTypeId);
                x.ConfigureConsumeTopology = false;
            });
            Event(() => JobSlotReleased, x =>
            {
                x.CorrelateById(m => m.Message.JobTypeId);
                x.ConfigureConsumeTopology = false;
            });
            Event(() => SetConcurrentJobLimit, x => x.CorrelateById(m => m.Message.JobTypeId));

            InstanceState(x => x.CurrentState, Active, Idle);

            During(Initial, Active, Idle,
                   When(JobSlotRequested)
                   .IfElse(context => context.IsSlotAvailable(options.HeartbeatTimeout),
                           allocate => allocate
                           .TransitionTo(Active),
                           unavailable => unavailable
                           .RespondAsync(context => context.Init <JobSlotUnavailable>(new { context.Data.JobId }))));

            During(Active,
                   When(JobSlotReleased)
                   .If(context => context.Instance.ActiveJobs.Any(x => x.JobId == context.Data.JobId),
                       release => release
                       .Then(context =>
            {
                var activeJob = context.Instance.ActiveJobs.FirstOrDefault(x => x.JobId == context.Data.JobId);
                if (activeJob != null)
                {
                    context.Instance.ActiveJobs.Remove(activeJob);
                    context.Instance.ActiveJobCount--;

                    LogContext.Debug?.Log("Released Job Slot: {JobId} ({JobCount}): {InstanceAddress}", activeJob.JobId,
                                          context.Instance.ActiveJobCount, activeJob.InstanceAddress);
                }
            }))
                   .If(context => context.Instance.ActiveJobCount == 0,
                       empty => empty.TransitionTo(Idle)));


            During(Initial,
                   When(SetConcurrentJobLimit)
                   .SetConcurrentLimit()
                   .TransitionTo(Idle));

            During(Active, Idle,
                   When(SetConcurrentJobLimit)
                   .SetConcurrentLimit()
                   );
        }
Example #9
0
        public JobAttemptStateMachine(JobServiceOptions options)
        {
            _options = options;

            SuspectJobRetryCount = options.SuspectJobRetryCount;
            SuspectJobRetryDelay = options.SuspectJobRetryDelay ?? options.SlotWaitTime;

            Event(() => StartJobAttempt, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => StartJobFaulted, x => x.CorrelateById(context => context.Message.Message.AttemptId));

            Event(() => AttemptCanceled, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => AttemptCompleted, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => AttemptFaulted, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => AttemptStarted, x => x.CorrelateById(context => context.Message.AttemptId));

            Event(() => AttemptStatus, x => x.CorrelateById(context => context.Message.AttemptId));

            Schedule(() => StatusCheckRequested, instance => instance.StatusCheckTokenId, x =>
            {
                x.Delay    = options.StatusCheckInterval;
                x.Received = r => r.CorrelateById(context => context.Message.AttemptId);
            });

            InstanceState(x => x.CurrentState, Starting, Running, Faulted, CheckingStatus, Suspect);

            During(Initial, Starting,
                   When(StartJobAttempt)
                   .Then(context =>
            {
                context.Instance.JobId        = context.Data.JobId;
                context.Instance.RetryAttempt = context.Data.RetryAttempt;
                context.Instance.ServiceAddress ??= context.Data.ServiceAddress;
            })
                   .SendStartJob()
                   .RespondAsync(context => context.Init <JobAttemptCreated>(context.Data))
                   .TransitionTo(Starting));

            During(Starting,
                   When(StartJobFaulted)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
                context.Instance.InstanceAddress ??= context.GetPayload <ConsumeContext>().SourceAddress;
            })
                   .SendJobAttemptFaulted(this)
                   .TransitionTo(Faulted));

            During(Initial, Starting, Running,
                   When(AttemptStarted)
                   .Then(context =>
            {
                context.Instance.JobId        = context.Data.JobId;
                context.Instance.Started      = context.Data.Timestamp;
                context.Instance.RetryAttempt = context.Data.RetryAttempt;
                context.Instance.InstanceAddress ??= context.Data.InstanceAddress;
            })
                   .ScheduleJobStatusCheck(this)
                   .TransitionTo(Running));

            During(Running, CheckingStatus, Suspect,
                   When(AttemptCompleted)
                   .Unschedule(StatusCheckRequested)
                   .Finalize(),
                   When(AttemptCanceled)
                   .Unschedule(StatusCheckRequested)
                   .Finalize(),
                   When(AttemptFaulted)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
                context.Instance.InstanceAddress ??= context.GetPayload <ConsumeContext>().SourceAddress;
            })
                   .Unschedule(StatusCheckRequested)
                   .TransitionTo(Faulted));

            During(Running,
                   When(StatusCheckRequested.Received)
                   .SendCheckJobStatus(this)
                   .TransitionTo(CheckingStatus)
                   .Catch <Exception>(eb => eb.TransitionTo(Suspect))
                   .ScheduleJobStatusCheck(this));

            During(CheckingStatus,
                   When(StatusCheckRequested.Received)
                   .SendCheckJobStatus(this)
                   .TransitionTo(Suspect)
                   .Catch <Exception>(eb => eb.TransitionTo(Suspect))
                   .ScheduleJobStatusCheck(this));

            During(Running, CheckingStatus, Suspect,
                   When(AttemptStatus, context => context.Data.Status == JobStatus.Running)
                   .TransitionTo(Running),
                   When(AttemptStatus, context => context.Data.Status == JobStatus.Canceled || context.Data.Status == JobStatus.Completed)
                   .Unschedule(StatusCheckRequested)
                   .Finalize(),
                   When(AttemptStatus, context => context.Data.Status == JobStatus.Faulted)
                   .Unschedule(StatusCheckRequested)
                   .TransitionTo(Faulted));

            During(Suspect,
                   When(StatusCheckRequested.Received)
                   .SendJobAttemptFaulted(this)
                   .TransitionTo(Faulted));

            During(Faulted,
                   Ignore(StatusCheckRequested.Received),
                   Ignore(AttemptFaulted));

            During(Initial,
                   When(AttemptCompleted)
                   .Finalize(),
                   When(AttemptCanceled)
                   .Finalize(),
                   When(StatusCheckRequested.Received)
                   .Finalize(),
                   When(AttemptStatus)
                   .Finalize());

            SetCompletedWhenFinalized();
        }
Example #10
0
        public JobStateMachine(JobServiceOptions options)
        {
            JobTypeSagaEndpointAddress    = options.JobTypeSagaEndpointAddress;
            JobSagaEndpointAddress        = options.JobSagaEndpointAddress;
            JobAttemptSagaEndpointAddress = options.JobAttemptSagaEndpointAddress;

            Event(() => JobSubmitted, x => x.CorrelateById(m => m.Message.JobId));

            Event(() => JobSlotAllocated, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => JobSlotUnavailable, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => AllocateJobSlotFaulted, x => x.CorrelateById(m => m.Message.Message.JobId));

            Event(() => JobAttemptCreated, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => StartJobAttemptFaulted, x => x.CorrelateById(m => m.Message.Message.JobId));

            Event(() => AttemptCanceled, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => AttemptCompleted, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => AttemptFaulted, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => AttemptStarted, x => x.CorrelateById(m => m.Message.JobId));

            Schedule(() => JobSlotWaitElapsed, instance => instance.JobSlotWaitToken, x =>
            {
                x.Delay    = options.SlotWaitTime;
                x.Received = r => r.CorrelateById(context => context.Message.JobId);
            });

            Schedule(() => JobRetryDelayElapsed, instance => instance.JobRetryDelayToken, x =>
            {
                x.Received = r => r.CorrelateById(context => context.Message.JobId);
            });

            InstanceState(x => x.CurrentState, Submitted, WaitingToStart, WaitingForSlot, Started, Completed, Faulted, Canceled, StartingJobAttempt,
                          AllocatingJobSlot, WaitingToRetry);

            Initially(
                When(JobSubmitted)
                .Then(OnJobSubmitted)
                .RequestJobSlot(this));

            During(AllocatingJobSlot,
                   When(JobSlotAllocated)
                   .RequestStartJob(this),
                   When(JobSlotUnavailable)
                   .WaitForJobSlot(this),
                   When(AllocateJobSlotFaulted)
                   .WaitForJobSlot(this));

            During(WaitingForSlot,
                   When(JobSlotWaitElapsed.Received)
                   .RequestJobSlot(this));

            During(StartingJobAttempt,
                   When(JobAttemptCreated)
                   .If(context => context.Data.AttemptId == context.Instance.AttemptId,
                       x => x.TransitionTo(WaitingToStart)),
                   When(StartJobAttemptFaulted)
                   .Then(context =>
            {
                context.Instance.Reason = context.Data.Exceptions.FirstOrDefault()?.Message;
            })
                   .PublishJobFaulted()
                   .TransitionTo(Faulted));

            During(Started, Completed, Faulted,
                   Ignore(JobAttemptCreated),
                   Ignore(StartJobAttemptFaulted));

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptStarted)
                   .Then(context => context.Instance.Started = context.Data.Timestamp)
                   .PublishJobStarted()
                   .TransitionTo(Started));

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptCompleted)
                   .Then(context =>
            {
                context.Instance.Completed = context.Data.Timestamp;
                context.Instance.Duration  = context.Data.Duration;
            })
                   .PublishJobCompleted()
                   .TransitionTo(Completed));

            During(Completed,
                   When(AttemptCompleted)
                   .PublishJobCompleted());

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptFaulted)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
            })
                   .IfElse(context => context.Data.RetryDelay.HasValue,
                           retry => retry
                           .Schedule(JobRetryDelayElapsed, context => context.Init <JobRetryDelayElapsed>(new { context.Data.JobId }),
                                     context => context.Data.RetryDelay.Value)
                           .TransitionTo(WaitingToRetry),
                           fault => fault
                           .PublishJobFaulted()
                           .TransitionTo(Faulted)));

            During(Faulted,
                   When(AttemptFaulted)
                   .PublishJobFaulted());

            During(WaitingToRetry,
                   Ignore(AttemptFaulted),
                   When(JobRetryDelayElapsed.Received)
                   .Then(context =>
            {
                context.Instance.AttemptId = NewId.NextGuid();
                context.Instance.RetryAttempt++;
            })
                   .RequestJobSlot(this)
                   );

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptCanceled)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
            })
                   .PublishJobCanceled()
                   .TransitionTo(Canceled));

            During(Canceled,
                   When(AttemptCanceled)
                   .PublishJobCanceled());

            WhenEnter(Completed, x => x.SendJobSlotReleased(options.JobTypeSagaEndpointAddress));
            WhenEnter(Canceled, x => x.SendJobSlotReleased(options.JobTypeSagaEndpointAddress));
            WhenEnter(Faulted, x => x.SendJobSlotReleased(options.JobTypeSagaEndpointAddress));
            WhenEnter(WaitingToRetry, x => x.SendJobSlotReleased(options.JobTypeSagaEndpointAddress));
        }
Example #11
0
        public JobStateMachine(JobServiceOptions options)
        {
            _options = options;

            Event(() => JobSubmitted, x => x.CorrelateById(m => m.Message.JobId));

            Event(() => JobSlotAllocated, x =>
            {
                x.CorrelateById(m => m.Message.JobId);
                x.ConfigureConsumeTopology = false;
            });
            Event(() => JobSlotUnavailable, x =>
            {
                x.CorrelateById(m => m.Message.JobId);
                x.ConfigureConsumeTopology = false;
            });
            Event(() => AllocateJobSlotFaulted, x =>
            {
                x.CorrelateById(m => m.Message.Message.JobId);
                x.ConfigureConsumeTopology = false;
            });

            Event(() => JobAttemptCreated, x =>
            {
                x.CorrelateById(m => m.Message.JobId);
                x.ConfigureConsumeTopology = false;
            });
            Event(() => StartJobAttemptFaulted, x =>
            {
                x.CorrelateById(m => m.Message.Message.JobId);
                x.ConfigureConsumeTopology = false;
            });

            Event(() => AttemptCanceled, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => AttemptCompleted, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => AttemptFaulted, x => x.CorrelateById(m => m.Message.JobId));
            Event(() => AttemptStarted, x => x.CorrelateById(m => m.Message.JobId));

            Event(() => JobCompleted, x => x.CorrelateById(m => m.Message.JobId));

            Schedule(() => JobSlotWaitElapsed, instance => instance.JobSlotWaitToken, x =>
            {
                x.Delay    = options.SlotWaitTime;
                x.Received = r =>
                {
                    r.CorrelateById(context => context.Message.JobId);
                    r.ConfigureConsumeTopology = false;
                };
            });

            Schedule(() => JobRetryDelayElapsed, instance => instance.JobRetryDelayToken, x =>
            {
                x.Received = r =>
                {
                    r.CorrelateById(context => context.Message.JobId);
                    r.ConfigureConsumeTopology = false;
                };
            });

            InstanceState(x => x.CurrentState, Submitted, WaitingToStart, WaitingForSlot, Started, Completed, Faulted, Canceled, StartingJobAttempt,
                          AllocatingJobSlot, WaitingToRetry);

            Initially(
                When(JobSubmitted)
                .InitializeJob()
                .RequestJobSlot(this));

            During(AllocatingJobSlot,
                   When(JobSlotAllocated)
                   .RequestStartJob(this),
                   When(JobSlotUnavailable)
                   .WaitForJobSlot(this),
                   When(AllocateJobSlotFaulted)
                   .WaitForJobSlot(this));

            During(WaitingForSlot,
                   When(JobSlotWaitElapsed.Received)
                   .RequestJobSlot(this));

            During(StartingJobAttempt,
                   When(StartJobAttemptFaulted)
                   .Then(context =>
            {
                context.Instance.Reason = context.Data.Exceptions.FirstOrDefault()?.Message;
            })
                   .NotifyJobFaulted()
                   .TransitionTo(Faulted));

            During(Started, Completed, Faulted,
                   Ignore(JobAttemptCreated),
                   Ignore(StartJobAttemptFaulted));

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptStarted)
                   .Then(context => context.Instance.Started = context.Data.Timestamp)
                   .PublishJobStarted()
                   .TransitionTo(Started));

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptCompleted)
                   .Then(context =>
            {
                context.Instance.Completed = context.Data.Timestamp;
                context.Instance.Duration  = context.Data.Duration;
            })
                   .NotifyJobCompleted()
                   .TransitionTo(Completed));

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptFaulted)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
                context.Instance.Reason  = context.Data.Exceptions?.Message ?? "Job Attempt Faulted (unknown reason)";
            })
                   .IfElse(context => context.Data.RetryDelay.HasValue,
                           retry => retry
                           .Schedule(JobRetryDelayElapsed, context => context.Init <JobRetryDelayElapsed>(new { context.Data.JobId }),
                                     context => context.Data.RetryDelay.Value)
                           .TransitionTo(WaitingToRetry),
                           fault => fault
                           .NotifyJobFaulted()
                           .TransitionTo(Faulted)));

            During(Completed,
                   When(AttemptCompleted)
                   .NotifyJobCompleted(),
                   When(AttemptStarted)
                   .Then(context => context.Instance.Started = context.Data.Timestamp)
                   .PublishJobStarted(),
                   When(JobCompleted)
                   .If(_ => options.FinalizeCompleted, x => x.Finalize()));

            During(Faulted,
                   When(AttemptFaulted)
                   .NotifyJobFaulted(),
                   When(AttemptStarted)
                   .Then(context => context.Instance.Started = context.Data.Timestamp)
                   .PublishJobStarted());

            During(WaitingToRetry,
                   Ignore(AttemptFaulted),
                   When(JobRetryDelayElapsed.Received)
                   .Then(context =>
            {
                context.Instance.AttemptId = NewId.NextGuid();
                context.Instance.RetryAttempt++;
            })
                   .RequestJobSlot(this)
                   );

            During(StartingJobAttempt, WaitingToStart, Started,
                   When(AttemptCanceled)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
                context.Instance.Reason  = "Job Attempt Canceled";
            })
                   .PublishJobCanceled()
                   .TransitionTo(Canceled));

            During(Canceled,
                   When(AttemptCanceled)
                   .PublishJobCanceled());

            WhenEnter(Completed, x => x.SendJobSlotReleased(this, JobSlotDisposition.Completed));
            WhenEnter(Canceled, x => x.SendJobSlotReleased(this, JobSlotDisposition.Canceled));
            WhenEnter(Faulted, x => x.SendJobSlotReleased(this, JobSlotDisposition.Faulted));
            WhenEnter(WaitingToRetry, x => x.SendJobSlotReleased(this, JobSlotDisposition.Faulted));

            SetCompletedWhenFinalized();
        }
Example #12
0
        public JobAttemptStateMachine(JobServiceOptions options)
        {
            Event(() => StartJobAttempt, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => StartJobFaulted, x => x.CorrelateById(context => context.Message.Message.AttemptId));

            Event(() => AttemptCanceled, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => AttemptCompleted, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => AttemptFaulted, x => x.CorrelateById(context => context.Message.AttemptId));
            Event(() => AttemptStarted, x => x.CorrelateById(context => context.Message.AttemptId));

            Schedule(() => StatusCheckRequested, instance => instance.StatusCheckTokenId, x =>
            {
                x.Delay    = options.StatusCheckInterval;
                x.Received = r => r.CorrelateById(context => context.Message.AttemptId);
            });

            InstanceState(x => x.CurrentState, Starting, Running, Faulted, Waiting);

            During(Initial, Starting,
                   When(StartJobAttempt)
                   .Then(context =>
            {
                context.Instance.JobId        = context.Data.JobId;
                context.Instance.RetryAttempt = context.Data.RetryAttempt;
                context.Instance.ServiceAddress ??= context.Data.ServiceAddress;
            })
                   .SendStartJob()
                   .RespondAsync(context => context.Init <JobAttemptCreated>(context.Data))
                   .TransitionTo(Starting));

            During(Starting,
                   When(StartJobFaulted)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
                context.Instance.InstanceAddress ??= context.GetPayload <ConsumeContext>().SourceAddress;
            })
                   .PublishJobAttemptFaulted()
                   .TransitionTo(Faulted));

            During(Initial, Starting, Running,
                   When(AttemptStarted)
                   .Then(context =>
            {
                context.Instance.JobId        = context.Data.JobId;
                context.Instance.Started      = context.Data.Timestamp;
                context.Instance.RetryAttempt = context.Data.RetryAttempt;
                context.Instance.InstanceAddress ??= context.Data.InstanceAddress;
            })
                   .Schedule(StatusCheckRequested, x => x.Init <JobStatusCheckRequested>(new { AttemptId = x.Instance.CorrelationId }))
                   .TransitionTo(Running));

            During(Running,
                   When(AttemptCompleted)
                   .Unschedule(StatusCheckRequested)
                   .Finalize(),
                   When(AttemptCanceled)
                   .Unschedule(StatusCheckRequested)
                   .Finalize(),
                   When(AttemptFaulted)
                   .Then(context =>
            {
                context.Instance.Faulted = context.Data.Timestamp;
                context.Instance.InstanceAddress ??= context.GetPayload <ConsumeContext>().SourceAddress;
            })
                   .Unschedule(StatusCheckRequested)
                   .TransitionTo(Faulted));

            During(Running,
                   When(StatusCheckRequested.Received));

            During(Faulted,
                   Ignore(StatusCheckRequested.Received),
                   Ignore(AttemptFaulted));
        }
Example #13
0
 public A_single_job_service_instance()
 {
     TestTimeout        = TimeSpan.FromSeconds(5);
     _jobServiceOptions = new JobServiceOptions();
 }
Example #14
0
 public A_single_job_service_instance_running_multiple_jobs()
 {
     TestTimeout        = TimeSpan.FromSeconds(10);
     _jobServiceOptions = new JobServiceOptions();
 }
Example #15
0
 public JobServiceEndpointConfigurationObserver(JobServiceOptions jobServiceOptions, Action <IReceiveEndpointConfigurator> configureEndpoint)
 {
     _jobServiceOptions = jobServiceOptions;
     _configureEndpoint = configureEndpoint;
 }