示例#1
0
        /// <summary>
        /// Run the job
        /// </summary>
        /// <param name="jobDetails">
        /// Job Details
        /// </param>
        /// <returns>
        /// Task Wrapper
        /// </returns>
        public async Task RunJobAsync(ScheduledJobDetails jobDetails)
        {
            await ExecuteJob(JobFactory(jobDetails.JobType), jobDetails);

            // Mark as done
            await Scheduler.CompleteJobIterationAsync(jobDetails);
        }
示例#2
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;
 }
示例#3
0
        /// <summary>
        /// Execute the file sync job
        /// </summary>
        /// <param name="details">
        /// Details of the job we are executing here.
        /// </param>
        /// <param name="logger">
        /// Handle to the logger
        /// </param>
        /// <remarks>
        /// This job:
        /// 1. If response is pending, it waits for response to be available
        /// 2. When response becomes available, the job processes it and puts flag that response is processed
        /// 3. If response is not pending, it checks to see if there are records to upload and uploads them
        /// 4. After file is sent to Amex, job puts flag that response is being waited on
        /// </remarks>
        public async Task Execute(ScheduledJobDetails details, CommerceLog logger)
        {
            Logger     = logger;
            JobDetails = details;
            Init();

            Logger.Exhaustive("Starting execution of job \r\n Details {0}", details);

            ////if (IsWaitingForResponse())
            ////{
            ////    // check the response
            ////    string[] responseFileNames = await RetrieveResponseFileNamesAsync().ConfigureAwait(false);
            ////    if (responseFileNames == null)
            ////    {
            ////        // we have to wait for response.
            ////        return;
            ////    }

            ////    await UploadResponseFilesToBlobStoreAsync(responseFileNames).ConfigureAwait(false);

            ////    // update job to mark, no response is expected now
            ////    UpdateResponsePendingIndicatorInJob("false");
            ////}
            ////else
            ////{
            ////    // process response files if present in blob store
            ////    await ProcessResponseFilesAsync().ConfigureAwait(false);

            ////    // if we reach here, we have either processed the response or no response is being waited on
            ////    // so create new request file if needed
            ////    string requestFile = await CreateNewRequestFileIfNeededAsync().ConfigureAwait(false);

            ////    if (requestFile != null)
            ////    {
            ////        await SendRequestFileAsync(requestFile).ConfigureAwait(false);

            ////        // successfully sent file -> update job to wait for response
            ////        UpdateResponsePendingIndicatorInJob("true");

            ////    }
            ////}

            // Process if any response files are pending
            string[] responseFileNames = await RetrieveResponseFileNamesAsync().ConfigureAwait(false);

            if (responseFileNames != null && responseFileNames.Length > 0)
            {
                await UploadResponseFilesToBlobStoreAsync(responseFileNames).ConfigureAwait(false);
            }

            // Process if any requests files are pending
            string requestFile = await CreateNewRequestFileIfNeededAsync().ConfigureAwait(false);

            if (requestFile != null)
            {
                await SendRequestFileAsync(requestFile).ConfigureAwait(false);
            }
        }
        /// <summary>
        /// Get a Job Runner <see cref="IJobRunner"/>
        /// </summary>
        /// <param name="jobDetails">
        /// Job Details
        /// </param>
        /// <param name="scheduler">
        /// Scheduler to use
        /// </param>
        /// <param name="commerceConfig">
        /// Configuration
        /// </param>
        /// <param name="log">
        /// Logger
        /// </param>
        /// <returns>
        /// Instance of a runner
        /// </returns>
        public static IJobRunner Runner(ScheduledJobDetails jobDetails, IScheduler scheduler, CommerceConfig commerceConfig, CommerceLog log)
        {
            if (jobDetails.Orchestrated)
            {
                return(new OrchestratedJobRunner(OrchestratedJobFactory.Create, scheduler, commerceConfig, log));
            }

            return(new SimpleJobRunner(ScheduledJobFactory.GetJobByType, log, scheduler));
        }
        /// <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);
        }
示例#6
0
        /// <summary>
        /// Process MasterCard rebate confirmation file job execution.
        /// </summary>
        /// <param name="details">
        /// Details of the job to be executed.
        /// </param>
        /// <param name="log">
        /// Log within which to log status of job processing.
        /// </param>
        /// <returns>
        /// A task to execute the  job.
        /// </returns>
        /// <remarks>
        /// Once complete, this job will schedule a corresponding MasterCardProcessRebateConfirmationJob.
        /// </remarks>
        public async Task Execute(ScheduledJobDetails details,
                                  CommerceLog log)
        {
            Log = log;
            Log.Verbose("Starting execution of job.\r\nDetails {0}", details);

            MasterCardRebateConfirmationBlobClient blobClient = MasterCardBlobClientFactory.MasterCardRebateConfirmationBlobClient(log);

            // Download files from MasterCard and upload them to the blob store.
            IFtpClient ftpClient = MasterCardFtpClientFactory.RebateConfirmationFtpClient(Log);

            string[] files = await ftpClient.DirectoryListAsync();

            if (files != null)
            {
                foreach (string fileName in files)
                {
                    using (MemoryStream memStream = new MemoryStream())
                    {
                        // Download the file from MasterCard.
                        await ftpClient.DownloadFileAsync(fileName, memStream).ConfigureAwait(false);

                        // Upload the file to the blob store.
                        memStream.Position = 0;
                        await blobClient.UploadAsync(memStream, fileName).ConfigureAwait(false);
                    }
                }
            }

            // Process all pending rebate confirmation files in the blob store.
            ICollection <string> fileNames = blobClient.RetrieveNamesOfPendingFiles();

            if (fileNames != null)
            {
                foreach (string fileName in fileNames)
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        // Download the file from the blob store.
                        memoryStream.Position = 0;
                        await blobClient.DownloadAsync(memoryStream, fileName).ConfigureAwait(false);

                        // Process the file.
                        memoryStream.Position = 0;
                        ISettlementFileProcessor rebateConfirmationProcessor = MasterCardFileProcessorFactory.MasterCardRebateConfirmationProcessor(memoryStream, fileName);
                        await rebateConfirmationProcessor.Process().ConfigureAwait(false);
                    }

                    // Mark the file as having been processed.
                    await blobClient.MarkAsCompleteAsync(fileName).ConfigureAwait(false);
                }
            }

            Log.Verbose("Execution of job {0} complete ", details.JobId);
        }
        /// <summary>
        /// Adds a redemption reward for the transaction in the context.
        /// </summary>
        internal void AddRedemptionRewards()
        {
            RedeemedDealInfo redeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];

            if (Context.Config.EnableRedemptionRewards == true && (ReimbursementTender)redeemedDealInfo.ReimbursementTenderId == ReimbursementTender.MicrosoftEarn)
            {
                IRewardOperations rewardOperations = CommerceOperationsFactory.RewardOperations(Context);
                Context[Key.RewardId] = Context.Config.FirstEarnRewardId;
                Context[Key.FirstEarnRewardAmount]      = Context.Config.FirstEarnRewardAmount;
                Context[Key.FirstEarnRewardExplanation] = Context.Config.FirstEarnRewardExplanation;
                ConcurrentDictionary <string, string> payload = new ConcurrentDictionary <string, string>();
                IScheduler scheduler = PartnerFactory.Scheduler(Context.Config.SchedulerQueueName,
                                                                Context.Config.SchedulerTableName,
                                                                Context.Config);
                if (rewardOperations.AddRedemptionReward() == ResultCode.Success)
                {
                    // Add a job to potentially reward user for their first Earn.
                    payload[Key.RewardPayoutId.ToString()]        = ((Guid)Context[Key.RewardPayoutId]).ToString();
                    payload[Key.PartnerCardId.ToString()]         = (string)Context[Key.PartnerCardId];
                    payload[Key.PartnerRedeemedDealId.ToString()] = redeemedDealInfo.PartnerRedeemedDealId;
                    payload[Key.RewardId.ToString()] = Context.Config.FirstEarnRewardId.ToString();
                    ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                    {
                        JobId          = Guid.NewGuid(),
                        JobType        = ScheduledJobType.ApplyRedemptionReward,
                        JobDescription = redeemedDealInfo.GlobalUserId.ToString(),
                        Orchestrated   = true,
                        Payload        = payload
                    };
                    scheduler.ScheduleJobAsync(scheduledJobDetails).Wait();
                }

                // Add a job to potentially reward the person who referred this user for this user's first Earn.
                Context[Key.RedeemedDealId] = ((RedeemedDeal)Context[Key.RedeemedDeal]).Id;
                Guid globalUserId = ((RedeemedDealInfo)Context[Key.RedeemedDealInfo]).GlobalUserId;
                Context[Key.GlobalUserId] = globalUserId;
                string userId = globalUserId.ToString();
                if (rewardOperations.AddReferredRedemptionReward() == ResultCode.Success)
                {
                    payload[Key.GlobalUserId.ToString()]  = userId;
                    payload[Key.ReferralEvent.ToString()] = ReferralEvent.Signup.ToString();
                    ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                    {
                        JobId          = Guid.NewGuid(),
                        JobType        = ScheduledJobType.ApplyReferralReward,
                        JobDescription = userId,
                        Orchestrated   = true,
                        StartTime      = DateTime.UtcNow,
                        Payload        = payload
                    };
                    scheduler.ScheduleJobAsync(scheduledJobDetails).Wait();
                }
            }
        }
示例#8
0
        public async Task Execute(ScheduledJobDetails details, CommerceLog log)
        {
            Log = log;

            Log.Verbose("Starting execution of job.\r\nDetails {0}", details);

            // Process rebate job for Visa.
            var visaProcessor = VisaSettlementProcessorFactory.VisaRebateProcessor();
            await visaProcessor.Process().ConfigureAwait(false);

            Log.Verbose("Exeuction of job {0} complete ", details.JobId);
        }
示例#9
0
        /// <summary>
        /// Async wrapper for Commerce Worker Role
        /// </summary>
        /// <returns>
        /// A Task to be waited on
        /// </returns>
        private async Task RunAsync()
        {
            Log.Verbose("Running Commerce Worker role.");

            Log.Verbose("Checking if we can start processing jobs ...");
            while (!ProcessJobs)
            {
                // is it fine ? too fast or slow?
                // we will finetune this after few tries on prod.
                Thread.Sleep(CommerceWorkerConfig.Instance.ProcessingLoopPollingInterval);
            }

            Log.Verbose("Entering processing loop.");

            do
            {
                try
                {
                    Thread.Sleep(CommerceWorkerConfig.Instance.ProcessingLoopPollingInterval);
                    ScheduledJobDetails jobDetails = await Scheduler.GetJobToProcessAsync();

                    if (jobDetails != null)
                    {
                        IJobRunner runner = JobRunnerFactory.Runner(
                            jobDetails, Scheduler, CommerceWorkerConfig.Instance, Log);
                        Log.Information("Running {0} job.", jobDetails.JobType);

                        Tuple <IScheduler, ScheduledJobDetails> timerState = new Tuple <IScheduler, ScheduledJobDetails>(Scheduler, jobDetails);
                        using (Timer tmr = new Timer(ExtendTimeout, timerState, WhenToExtendTimeout, WhenToExtendTimeout))
                        {
                            await runner.RunJobAsync(jobDetails);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Critical("An unknown error occurred during processing.", ex);
                }
            }while (ProcessJobs);

            Log.Information("Processing loop has exited.");

            // We are no longer processing jobs new now...just waiting to be killed when processing ends.
            while (!ExitRole)
            {
#if !IntDebug && !IntRelease
                Log.Information("Wating for role to exit ...");
#endif
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }

            Log.Information("Role is shutting down ...");
        }
        /// <summary>
        /// Process MasterCard rebate file job execution.
        /// </summary>
        /// <param name="details">
        /// Details of the job to be executed.
        /// </param>
        /// <param name="log">
        /// Log within which to log status of job processing.
        /// </param>
        /// <returns>
        /// A task to execute the  job.
        /// </returns>
        public async Task Execute(ScheduledJobDetails details,
                                  CommerceLog log)
        {
            Log = log;

            Log.Verbose("Starting execution of job.\r\nDetails {0}", details);

            // Process rebate job for MasterCard.
            ISettlementFileProcessor masterCardProcessor = MasterCardFileProcessorFactory.MasterCardRebateProcessor(UploadRebateFile);
            await masterCardProcessor.Process().ConfigureAwait(false);

            Log.Verbose("Exeuction of job {0} complete ", details.JobId);
        }
示例#11
0
        /// <summary>
        /// Process Pts File Job Execution
        /// </summary>
        /// <param name="details">
        /// Details of the job we are executing here.
        /// </param>
        /// <param name="logger">
        /// Handle to the logger
        /// </param>
        public async Task Execute(ScheduledJobDetails details, CommerceLog logger)
        {
            Logger = logger;

            Logger.Verbose("Starting execution of job \r\n " +
                           "Details {0}", details);

            // Process PTS Job for FDC
            ISettlementFileProcessor ptsProcessor = FirstDataFileProcessorFactory.FirstDataPtsProcessor(OnPtsBuild);
            await ptsProcessor.Process().ConfigureAwait(false);

            Logger.Verbose("Exeuction of job {0} complete ", details.JobId);
        }
        /// <summary>
        /// Process Amex Statement Credi File Job Execution
        /// </summary>
        /// <param name="details">
        /// Details of the job we are executing here.
        /// </param>
        /// <param name="logger">
        /// Handle to the logger
        /// </param>
        public async Task Execute(ScheduledJobDetails details, CommerceLog logger)
        {
            Logger = logger;

            Logger.Verbose("Starting execution of job \r\n Details {0}", details);

            // Process Statement Credit Acknowledgment files
            await ProcessStatementCreditResponse();

            // Process Statement Credit files
            StatementCreditFileBuilder builder = new StatementCreditFileBuilder();
            await builder.Build(OnStmtCreditFileBuild).ConfigureAwait(false);

            Logger.Verbose("Execution of job {0} complete ", details.JobId);
        }
示例#13
0
 /// <summary>
 /// Excute the job
 /// </summary>
 /// <param name="job">
 /// The job to execute
 /// </param>
 /// <param name="details">
 /// Job Details
 /// </param>
 /// <returns>
 /// Async Task Wrapper
 /// </returns>
 internal async Task ExecuteJob(IScheduledJob job, ScheduledJobDetails details)
 {
     try
     {
         await job.Execute(details, Log);
     }
     catch (Exception exception)
     {
         Log.Error(" Error in execution job \r\n" +
                   " Details : {0}",
                   exception,
                   (int)ResultCode.JobExecutionError,
                   details);
     }
 }
        /// <summary>
        /// Process Amex Transaction Log File Job Execution
        /// </summary>
        /// <param name="details">
        /// Details of the job we are executing here.
        /// </param>
        /// <param name="logger">
        /// Handle to the logger
        /// </param>
        public async Task Execute(ScheduledJobDetails details, CommerceLog logger)
        {
            logger.Verbose("Starting execution of job \r\n Details {0}", details);
            string connectionString = CloudConfigurationManager.GetSetting("Lomo.Commerce.Fdc.Blob.ConnectionString");
            AmexTransactionLogSftpClient     ftpClient  = new AmexTransactionLogSftpClient(logger);
            AmexTransactionLogFileBlobClient blobClient = AmexBlobFactory.TransactionLogBlobClient(connectionString, logger);

            string[] files = await ftpClient.DirectoryListAsync("AXP_MSF_TLOG", "outbox");

            if (files != null)
            {
                foreach (string fileName in files)
                {
                    MemoryStream memStream = new MemoryStream();
                    await ftpClient.DownloadFileAsync(fileName, memStream, "outbox").ConfigureAwait(false);

                    // lets upload it to blob
                    memStream.Position = 0;
                    await blobClient.UploadAsync(memStream, fileName).ConfigureAwait(false);
                }
            }

            ICollection <string> listOfFiles = blobClient.RetrieveFilesToProcess();

            if (listOfFiles != null)
            {
                foreach (string fileName in listOfFiles)
                {
                    MemoryStream memStream = new MemoryStream();
                    memStream.Position = 0;
                    await blobClient.DownloadAsync(memStream, fileName).ConfigureAwait(false);

                    memStream.Position = 0;
                    TransactionLogFileProcessor transactionLogFileProcessor = new TransactionLogFileProcessor()
                    {
                        TransactionLogFileName   = fileName,
                        TransactionLogFileStream = memStream
                    };
                    await transactionLogFileProcessor.Process().ConfigureAwait(false);

                    await blobClient.MarkAsProcessedAsync(fileName).ConfigureAwait(false);
                }
            }

            logger.Verbose("Execution of job {0} complete ", details.JobId);
        }
示例#15
0
        /// <summary>
        /// 1. Process the FDC Extract file.
        /// 2. Schedule the Process Pts Job
        /// </summary>
        /// <param name="details">
        /// Details of the job we are executing here.
        /// </param>
        /// <param name="logger">
        /// Handle to the logger
        /// </param>
        public async Task Execute(ScheduledJobDetails details, CommerceLog logger)
        {
            logger.Verbose("Starting execution of job \r\n " +
                           "Details {0}", details);

            string     connectionString = CloudConfigurationManager.GetSetting("Lomo.Commerce.Fdc.Blob.ConnectionString");
            IFtpClient ftpClient        = FirstDataFtpClientFactory.FirstDataExtractFtpClient(logger);

            FirstDataExtractBlobClient blobClient = FirstDataBlobClientFactory.FirstDataExtractBlobClient(connectionString, logger);

            string[] files = await ftpClient.DirectoryListAsync();

            if (files != null)
            {
                foreach (string fileName in files)
                {
                    MemoryStream memStream = new MemoryStream();
                    await ftpClient.DownloadFileAsync(fileName, memStream).ConfigureAwait(false);

                    // lets upload it to blob
                    memStream.Position = 0;
                    await blobClient.UploadAsync(memStream, fileName).ConfigureAwait(false);
                }
            }

            // Now try to run all the pending files in the blob
            ICollection <string> listOfFiles = blobClient.RetrieveFilesToProcess();

            if (listOfFiles != null)
            {
                foreach (string fileName in listOfFiles)
                {
                    MemoryStream memStream = new MemoryStream();
                    memStream.Position = 0;
                    await blobClient.DownloadAsync(memStream, fileName).ConfigureAwait(false);

                    memStream.Position = 0;
                    ISettlementFileProcessor extractProcessor = FirstDataFileProcessorFactory.FirstDataExtractProcessor(fileName, memStream);
                    await extractProcessor.Process().ConfigureAwait(false);

                    await blobClient.MarkAsProcessedAsync(fileName).ConfigureAwait(false);
                }
            }

            logger.Verbose("Execution of job {0} complete ", details.JobId);
        }
示例#16
0
        public Task Execute(ScheduledJobDetails details, CommerceLog logger)
        {
            this.log = logger;
            DateTime startDate;
            DateTime endDate = DateTime.UtcNow.Date;

            //Check if we have the last successful report run date in the payload
            if (details.Payload != null && details.Payload.ContainsKey(RewardNetworkReportLastRunDate))
            {
                string strLastRunDate = details.Payload[RewardNetworkReportLastRunDate];
                if (!DateTime.TryParse(strLastRunDate, out startDate))
                {
                    log.Error(
                        "LastRunDate specified for the RewardNetworksReportJob in the payload is invalid. Invalid value is {0}",
                        null, (int)ResultCode.JobExecutionError, strLastRunDate);
                }
                //If we have the last successful run date, add a day to it to set as the start date for the next run
                startDate = startDate.AddDays(1).Date;
            }
            else
            {
                startDate = DateTime.UtcNow.AddDays(-1).Date;
            }

            RewardNetworkReportProcessor rewardNetworkReportProcessor = new RewardNetworkReportProcessor(Context);

            rewardNetworkReportProcessor.GenerateReportForDays(startDate, endDate);
            DateTime lastSuccessfulRun = (DateTime)Context[Key.RewardNetworkReportLastRunDate];

            if (details.Payload == null)
            {
                details.Payload = new Dictionary <string, string>();
            }

            if (details.Payload.ContainsKey(RewardNetworkReportLastRunDate))
            {
                details.Payload[RewardNetworkReportLastRunDate] = lastSuccessfulRun.ToString("yyyy-MM-dd");
            }

            this.log.Verbose("Execution of job {0} complete ", details.JobId);

            return(Task.FromResult(0));
        }
示例#17
0
        /// <summary>
        /// Process the rewards if applicable
        /// </summary>
        /// <param name="settlementDetail">
        /// Settlement Details
        /// </param>
        /// <returns>
        /// Async Task Wrapper
        /// </returns>
        internal async Task ProcessRewardPayoutAsync(SettlementDetail settlementDetail)
        {
            if (settlementDetail.TransactionType == TransactionType.SettlementRedemption)
            {
                // First add a redemption reward to the redeeming user if they're enabled.
                if (EnableRedemptionRewards == true && WorkerActions.RewardRedemption(RewardOperations, Context) == ResultCode.Success)
                {
                    // Add job to process the reward payout. Note that this job will be scheduled 30 minutes in the
                    // future to guard against applying a reward for a transaction that was reversed in a later
                    // record.
                    ConcurrentDictionary <string, string> payload = new ConcurrentDictionary <string, string>();
                    payload[Key.RewardPayoutId.ToString()]        = ((Guid)Context[Key.RewardPayoutId]).ToString();
                    payload[Key.PartnerCardId.ToString()]         = (string)Context[Key.PartnerCardId];
                    payload[Key.PartnerRedeemedDealId.ToString()] = settlementDetail.TransactionId;

                    IScheduler scheduler = PartnerFactory.Scheduler(CommerceWorkerConfig.Instance.SchedulerQueueName,
                                                                    CommerceWorkerConfig.Instance.SchedulerTableName,
                                                                    CommerceWorkerConfig.Instance);
                    ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                    {
                        JobId          = Guid.NewGuid(),
                        JobType        = ScheduledJobType.ApplyRedemptionReward,
                        JobDescription = settlementDetail.ConsumerId,
                        Orchestrated   = true,
                        StartTime      = DateTime.UtcNow.AddMinutes(30),
                        Payload        = payload
                    };

                    await scheduler.ScheduleJobAsync(scheduledJobDetails).ConfigureAwait(false);
                }

                // Then add a referred redemption reward to the user who referred the redeeming user.
                WorkerActions.RewardReferredRedemption(RewardOperations, Context);
            }
            else
            {
                Context.Log.Verbose("No Bing Reward can be given for a reversed transaction.");
            }
        }
示例#18
0
        /// <summary>
        /// Queues claiming already claimed deals for the new card.
        /// </summary>
        /// <param name="response">
        /// The AddCardResponse being built.
        /// </param>
        private void QueueClaimingDeals(AddCardResponse response)
        {
            Context.Log.Verbose("Queueing claiming user's existing claimed deals for the new card.");
            string userId = ((User)Context[Key.User]).GlobalId.ToString();
            ConcurrentDictionary <string, string> payload = new ConcurrentDictionary <string, string>();

            payload[Key.GlobalUserId.ToString()] = userId;
            payload[Key.CardId.ToString()]       = General.IntegerFromGuid(response.NewCardId).ToString();
            ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
            {
                JobId          = Guid.NewGuid(),
                JobType        = ScheduledJobType.ClaimDiscountsForNewCard,
                JobDescription = userId,
                Orchestrated   = true,
                StartTime      = DateTime.UtcNow,
                Payload        = payload
            };
            IScheduler scheduler = PartnerFactory.Scheduler(CommerceServiceConfig.Instance.SchedulerQueueName,
                                                            CommerceServiceConfig.Instance.SchedulerTableName,
                                                            CommerceServiceConfig.Instance);

            scheduler.ScheduleJobAsync(scheduledJobDetails).Wait();
        }
示例#19
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;
            }
        }
        /// <summary>
        /// Process the transaction log file
        /// </summary>
        /// <returns>
        /// Async Task Wrapper
        /// </returns>
        public async Task Process()
        {
            TransactionLogParser transactionLogParser = new TransactionLogParser(Context.Log);
            TransactionLogFile   transactionLogFile   = transactionLogParser.Parse(TransactionLogFileName, TransactionLogFileStream);

            if (transactionLogFile != null)
            {
                foreach (TransactionLogDetail detail in transactionLogFile.TransactionLogRecords)
                {
                    // block the reversed transactions
                    if (TransactionIdSet.Contains(detail.TransactionId) || detail.TransactionAmount <= 0)
                    {
                        continue;
                    }

                    TransactionIdSet.Add(detail.TransactionId);

                    // 1. process the detail record here -> Insert as redeemed deal
                    RedeemedDeal redeemedDeal = new RedeemedDeal()
                    {
                        AnalyticsEventId = Guid.NewGuid()
                    };
                    Context[Key.RedeemedDeal] = redeemedDeal;
                    MarshalRedeemDeal(detail);
                    ResultCode result = RedeemedDealOperations.AddRedeemedDeal();

                    //2. If the record was processed successfully, attempt to add a redemption reward if applicable and analytics
                    if (result == ResultCode.Created)
                    {
                        RedeemedDealInfo redemptionInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];
                        // First add a redemption reward to the redeeming user if they're enabled.
                        if (EnableRedemptionRewards)
                        {
                            if (WorkerActions.RewardRedemption(RewardOperations, Context) == ResultCode.Success)
                            {
                                // Add job to process the reward payout.
                                ConcurrentDictionary <string, string> payload = new ConcurrentDictionary <string, string>();
                                payload[Key.RewardPayoutId.ToString()]        = ((Guid)Context[Key.RewardPayoutId]).ToString();
                                payload[Key.PartnerCardId.ToString()]         = (string)Context[Key.PartnerCardId];
                                payload[Key.PartnerRedeemedDealId.ToString()] = redemptionInfo.PartnerRedeemedDealId;

                                IScheduler scheduler = PartnerFactory.Scheduler(CommerceWorkerConfig.Instance.SchedulerQueueName,
                                                                                CommerceWorkerConfig.Instance.SchedulerTableName,
                                                                                CommerceWorkerConfig.Instance);
                                ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                                {
                                    JobId          = Guid.NewGuid(),
                                    JobType        = ScheduledJobType.ApplyRedemptionReward,
                                    JobDescription = redemptionInfo.GlobalUserId.ToString(),
                                    Orchestrated   = true,
                                    Payload        = payload
                                };

                                await scheduler.ScheduleJobAsync(scheduledJobDetails).ConfigureAwait(false);
                            }
                        }

                        // Then add a referred redemption reward to the user who referred the redeeming user.
                        Context[Key.RedeemedDealId] = ((RedeemedDeal)Context[Key.RedeemedDeal]).Id;
                        Context[Key.GlobalUserId]   = ((RedeemedDealInfo)Context[Key.RedeemedDealInfo]).GlobalUserId;
                        WorkerActions.RewardReferredRedemption(RewardOperations, Context);

                        // Update analytics.
                        // For FDC this happens at AUTH time
                        // Butfor Amex flow, we put analytics at the time of Transaction File Processing
                        SharedUserLogic sharedUserLogic = new SharedUserLogic(Context,
                                                                              CommerceOperationsFactory.UserOperations(Context));
                        Context[Key.GlobalUserId] = redemptionInfo.GlobalUserId;
                        User user = sharedUserLogic.RetrieveUser();
                        Analytics.AddRedemptionEvent(redemptionInfo.GlobalUserId, redeemedDeal.AnalyticsEventId, user.AnalyticsEventId,
                                                     redemptionInfo.ParentDealId, redemptionInfo.Currency,
                                                     redeemedDeal.AuthorizationAmount, redemptionInfo.DiscountAmount,
                                                     redemptionInfo.GlobalId, (string)Context[Key.PartnerMerchantId],
                                                     CommerceWorkerConfig.Instance);
                    }
                }
            }
        }
示例#21
0
 /// <summary>
 /// Ping Job - Just logs the message.
 /// </summary>
 /// <param name="details">
 /// Details of the job we are executing here.
 /// </param>
 /// <param name="logger">
 /// Handle to the logger
 /// </param>
 public Task Execute(ScheduledJobDetails details, CommerceLog logger)
 {
     return(Task.Factory.StartNew(() => logger.Information("Executing ping job \r\n " +
                                                           "Details {0}", details)));
 }
 public Task Execute(ScheduledJobDetails details, CommerceLog logger)
 {
     return(Task.Factory.StartNew(() => { }));
 }
        /// <summary>
        /// Exponentially backoff the next run time of a job after every failure (Non-Terminal) upto a defined MAX.
        /// Currently, only one time jobs are exponentially backed off, and recurring jobs are just scheduled for next occurence.
        /// </summary>
        /// <param name="scheduler">
        /// Instance of the Scheduler
        /// </param>
        /// <param name="jobDetails">
        /// Scheduled Job Details.
        /// </param>
        /// <returns>
        /// Async Task Wrapper
        /// </returns>
        public static async Task ExponentiallyBackoffAsync(this IScheduler scheduler, ScheduledJobDetails jobDetails, CommerceLog log)
        {
            // this branch should not happen once we schedule the job once.
            if (jobDetails != null && jobDetails.Recurrence != null)
            {
                // if job is scheduled to run only once
                if (jobDetails.Recurrence.Count == 1)
                {
                    // initialize retry count if it does not exist
                    if (jobDetails.Payload == null)
                    {
                        jobDetails.Payload = new Dictionary <string, string>();
                        jobDetails.Payload["RetryCount"] = "0";
                    }
                    else if (!jobDetails.Payload.ContainsKey("RetryCount"))
                    {
                        jobDetails.Payload["RetryCount"] = "0";
                    }

                    int retryCount;
                    if (!int.TryParse(jobDetails.Payload["RetryCount"], out retryCount))
                    {
                        retryCount = 0;
                    }

                    //Important: Since the job is a run once job, so recurrence for the next retry is solely
                    // dependent on the retry interval. Past recurrence is immaterial.
                    jobDetails.Recurrence = new Recurrence()
                    {
                        Frequency = RecurrenceFrequency.Second,
                        Count     = 1,
                        Interval  = GetWaitTimeInSeconds(retryCount)
                    };

                    log.Verbose("Job Id {0} has been retried {1} times, back off to try the next time after {2} seconds",
                                jobDetails.JobId,
                                retryCount,
                                jobDetails.Recurrence.Interval);

                    // increment retry count in payload
                    jobDetails.Payload["RetryCount"] = (retryCount + 1).ToString(CultureInfo.InvariantCulture);

                    // schedule it to run later
                    await scheduler.UpdateJobAsync(jobDetails).ConfigureAwait(false);
                }
                else // recurring job
                {
                    // just mark current iteration as done. We will try again next time
                    await scheduler.CompleteJobIterationAsync(jobDetails).ConfigureAwait(false);
                }
            }
            else
            {
                log.Warning("After first run of job, job or recurrence should not be null.");
                await Task.Factory.StartNew(() => { }).ConfigureAwait(false);
            }
        }
 /// <summary>
 /// Initializes the IOrchestratedJob instance
 /// </summary>
 /// <param name="jobDetails">
 /// The details of the job being run.
 /// </param>
 /// <param name="scheduler">
 /// The scheduler managing the jobs.
 /// </param>
 public void Initialize(ScheduledJobDetails jobDetails,
                        IScheduler scheduler)
 {
     JobDetails = jobDetails;
     Scheduler  = scheduler;
 }
        /// <summary>
        /// Process the response file
        /// </summary>
        /// <returns>
        /// Async Task Wrapper
        /// </returns>
        public virtual async Task <bool> ProcessAsync()
        {
            OfferRegistrationResponseFileParser parser       = new OfferRegistrationResponseFileParser(Context.Log);
            OfferRegistrationResponseFile       responseFile = parser.Parse(ResponseFileName, ResponseFileStream);
            bool submissionValid = true;

            if (responseFile != null)
            {
                if (responseFile.Header.ResponseCode == "A")
                {
                    foreach (OfferRegistrationResponseDetail record in responseFile.ResponseRecords)
                    {
                        Context[Key.PartnerDealId] = record.OfferId;
                        Context[Key.Partner]       = Partner.Amex;
                        IDealOperations dealOperations = CommerceOperationsFactory.DealOperations(Context);
                        Guid?           discountId     = dealOperations.RetrieveDiscountIdFromPartnerDealId();
                        Context[Key.GlobalDealId] = discountId.Value;
                        SharedDealLogic dealLogic = new SharedDealLogic(Context, CommerceOperationsFactory.DealOperations(Context));
                        Deal            deal      = dealLogic.RetrieveDeal();

                        // for each record - check the status and process accordingly
                        if (record.ResponseCode == "A")
                        {
                            if (record.ActionCode == OfferRegistrationActionCodeType.Add)
                            {
                                // Possible Race condition in this part of the code
                                // By time time we check whether all partners are registered, things could change in DB
                                // this is not a concern right now but we need to figure it out.
                                bool allOtherPartnersRegistered = true;
                                foreach (PartnerDealInfo partnerDealInfo in deal.PartnerDealInfoList)
                                {
                                    if (partnerDealInfo.PartnerId != Partner.Amex)
                                    {
                                        if (partnerDealInfo.PartnerDealRegistrationStatusId !=
                                            PartnerDealRegistrationStatus.Complete)
                                        {
                                            allOtherPartnersRegistered = false;
                                            break;
                                        }
                                    }
                                }

                                // now update deal status
                                deal.DealStatusId = DealStatus.PendingAutoLinking;
                                foreach (PartnerDealInfo partnerDealInfo in deal.PartnerDealInfoList)
                                {
                                    if (partnerDealInfo.PartnerId == Partner.Amex)
                                    {
                                        partnerDealInfo.PartnerDealRegistrationStatusId = PartnerDealRegistrationStatus.Complete;
                                    }
                                }
                                Context[Key.Deal] = deal;
                                dealOperations.RegisterDeal();

                                if (allOtherPartnersRegistered)
                                {
                                    // schedule autolinking
                                    ConcurrentDictionary <string, string> payload = new ConcurrentDictionary <string, string>();
                                    payload[Key.GlobalDealId.ToString()] = deal.GlobalId.ToString();
                                    ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                                    {
                                        JobId        = Guid.NewGuid(),
                                        JobType      = ScheduledJobType.ClaimDiscountForExistingCards,
                                        Orchestrated = true,
                                        StartTime    = DateTime.UtcNow,
                                        Payload      = payload
                                    };
                                    await Scheduler.ScheduleJobAsync(scheduledJobDetails).ConfigureAwait(false);
                                }
                            }
                            else if (record.ActionCode == OfferRegistrationActionCodeType.Update)
                            {
                                // previously registered, and update was successful.
                                foreach (PartnerDealInfo partnerDealInfo in deal.PartnerDealInfoList)
                                {
                                    if (partnerDealInfo.PartnerId == Partner.Amex)
                                    {
                                        partnerDealInfo.PartnerDealRegistrationStatusId = PartnerDealRegistrationStatus.Complete;
                                    }
                                }
                                Context[Key.Deal] = deal;
                                dealOperations.RegisterDeal();
                                // TODO:Tell Deal Server we are done.
//                                ConcurrentDictionary<string, string> payload = new ConcurrentDictionary<string, string>();
//                                payload[Key.DealId.ToString()] = deal.Id.ToString();
//                                ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
//                                {
//                                    JobId = Guid.NewGuid(),
//                                    JobType = ScheduledJobType.DiscountActivationJob,
//                                    Orchestrated = false,
//                                    StartTime = DateTime.UtcNow,
//                                    Payload = payload
//                                };
//                                await Scheduler.ScheduleJobAsync(scheduledJobDetails).ConfigureAwait(false);
                            }
                        }
                        else
                        {
                            Context.Log.Warning("Attempt to register a deal with Amex failed\r\nOffer Id {0}\r\n Reason {1}", (int)ResultCode.SubmissionRejected, record.OfferId, record.ResponseCodeMessage);
                            // update the deal to reflect error
                            foreach (PartnerDealInfo partnerDealInfo in deal.PartnerDealInfoList)
                            {
                                if (partnerDealInfo.PartnerId == Partner.Amex)
                                {
                                    partnerDealInfo.PartnerDealRegistrationStatusId = PartnerDealRegistrationStatus.Error;
                                }
                            }
                            Context[Key.Deal] = deal;
                            dealOperations.RegisterDeal();
                        }
                    }
                }
                else
                {
                    // file submission was rejected.
                    submissionValid = false;
                }
            }
            return(submissionValid);
        }