Exemple #1
0
 /// <summary>
 /// Initializes a new instance of the JobOrchestrator class.
 /// </summary>
 /// <param name="job">
 /// The job being executed.
 /// </param>
 /// <param name="jobDetails">
 /// Details about the job being executed.
 /// </param>
 /// <param name="log">
 /// The CommerceLog object through which log entries can be made.
 /// </param>
 public JobOrchestrator(IOrchestratedJob job,
                        ScheduledJobDetails jobDetails,
                        CommerceLog log)
 {
     Job        = job;
     JobDetails = jobDetails;
     Log        = log;
 }
        /// <summary>
        /// Creates and initializes an instance of IOrchestratedJob of the specified type.
        /// </summary>
        /// <param name="jobDetails">
        /// Details describing the IOrchestratedJob type to create.
        /// </param>
        /// <param name="scheduler">
        /// The scheduler managing the job.
        /// </param>
        /// <param name="log">
        /// The object through which log entries can be made.
        /// </param>
        /// <returns>
        /// An instance of IOrchestratedJob of the specified type.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// * Parameter jobDetails cannot be null.
        /// -OR-
        /// * Parameter log cannot be null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Parameter JobDetails does not specify a valid IOrchestratedJob type.
        /// </exception>
        public static IOrchestratedJob Create(ScheduledJobDetails jobDetails,
                                              IScheduler scheduler,
                                              CommerceLog log)
        {
            if (jobDetails == null)
            {
                throw new ArgumentNullException("jobDetails", "Parameter jobDetails cannot be null.");
            }

            if (log == null)
            {
                throw new ArgumentNullException("log", "Parameter log cannot be null.");
            }

            IOrchestratedJob result = null;

            if (jobDetails.Payload != null)
            {
                switch (jobDetails.JobType)
                {
                case ScheduledJobType.ApplyReferralReward:
                    result = new ApplyReferralRewardJob(log);
                    break;

                case ScheduledJobType.ApplyRedemptionReward:
                    result = new ApplyRedemptionRewardJob(log);
                    break;

                case ScheduledJobType.ClaimDiscountsForNewCard:
                    result = new ClaimDiscountsForNewCardJob(log);
                    break;

                case ScheduledJobType.ClaimDiscountForExistingCards:
                    result = new ClaimDiscountForExistingCardsJob(log);
                    break;

                case ScheduledJobType.AmexOfferRegistration:
                    result = new AmexOfferRegistrationJob(log);
                    break;

                default:
                    throw new ArgumentException("Parameter JobDetails does not specify a valid IOrchestratedJob type.",
                                                "jobDetails");
                }

                result.Initialize(jobDetails, scheduler);
            }
            else
            {
                log.Error("{0} orchestrated job contains no Payload.", null, jobDetails.JobType,
                          ResultCode.JobContainsNoPayload);
            }

            return(result);
        }
Exemple #3
0
        /// <summary>
        /// Runs the orchestrated job described in the specified ScheduleJobDetails object.
        /// </summary>
        /// <param name="jobDetails">
        /// The details of the orchestrated job to run.
        /// </param>
        /// <remarks>
        /// A job is limited to MaxJobRetries runs, even for successful runs, before being placed back in the queue to ensure
        /// that a job in an endless loop does not take down the entire worker role (pre-emptive multi-tasking.) But, if the job
        /// times out, another worker instance may attempt to run the job while it's still being run in another instance. Going
        /// forward, some mechanism to halt execution at time out should be added.
        /// </remarks>
        public async Task RunJobAsync(ScheduledJobDetails jobDetails)
        {
            OrchestratedExecutionResult executionResult;
            int maxRetries     = CommerceConfig.MaxJobRetries;
            int retryLatency   = CommerceConfig.InitialJobRetryLatency;
            int tryCount       = 0;
            int tasksPerformed = 0;

            IOrchestratedJob job             = JobFactory(jobDetails, Scheduler, Log);
            JobOrchestrator  jobOrchestrator = null;

            if (job != null)
            {
                jobOrchestrator = new JobOrchestrator(job, jobDetails, Log);
            }

            if (jobOrchestrator != null)
            {
                do
                {
                    try
                    {
                        Task <OrchestratedExecutionResult> executionResultTask =
                            Task.Factory.StartNew(() => jobOrchestrator.Execute(out tasksPerformed));
                        executionResult = await executionResultTask;
                    }
                    catch (InvalidOperationException ex)
                    {
                        ResultCode resultCode;
                        if (Enum.TryParse <ResultCode>(ex.Message, out resultCode) == true)
                        {
                            executionResult = OrchestratedExecutionResult.NonTerminalError;
                        }
                        else
                        {
                            throw;
                        }
                    }
                    Log.Verbose("{0} orchestrated job completed {1} steps with result {2}.", jobDetails.JobType,
                                tasksPerformed, executionResult);

                    if (executionResult == OrchestratedExecutionResult.NonTerminalError && tryCount <= maxRetries)
                    {
                        Log.Verbose("Waiting {0} milliseconds before retrying job execution.", retryLatency);
                        Thread.Sleep(retryLatency);
                        retryLatency *= 2;
                    }

                    tryCount++;
                }while (executionResult != OrchestratedExecutionResult.TerminalError &&
                        tasksPerformed > 0 &&
                        tryCount <= maxRetries);

                // tear down the job here.
                executionResult = jobOrchestrator.Cleanup(executionResult);
            }
            else
            {
                executionResult = OrchestratedExecutionResult.TerminalError;
            }

            StringBuilder stringBuilder = new StringBuilder("{0} orchestrated job completed with result {1}.");

            if (executionResult == OrchestratedExecutionResult.NonTerminalError)
            {
                stringBuilder.Append(" Job will be sent to the back of the queue for reprocessing.");
            }
            Log.Information(stringBuilder.ToString(), jobDetails.JobType, executionResult);

            // Update Scheduler with result of running the job.
            switch (executionResult)
            {
            case OrchestratedExecutionResult.Success:
                await Scheduler.CompleteJobIterationAsync(jobDetails).ConfigureAwait(false);

                break;

            case OrchestratedExecutionResult.TerminalError:
                jobDetails.JobState = ScheduledJobState.Canceled;
                jobDetails.Payload  = null;
                await Scheduler.UpdateJobAsync(jobDetails).ConfigureAwait(false);

                break;

            case OrchestratedExecutionResult.NonTerminalError:
                await Scheduler.ExponentiallyBackoffAsync(jobDetails, Log).ConfigureAwait(false);

                break;
            }
        }