Example #1
0
        /// <summary>
        /// Mark the job iteration as complete.
        /// </summary>
        /// <param name="jobDetails">
        /// The details of the job which we want to mark as complete
        /// </param>
        /// <returns>
        /// Task wrapper for async operation
        /// </returns>
        public async Task CompleteJobIterationAsync(ScheduledJobDetails jobDetails)
        {
            Log.Info("Incoming request to complete a job iteration \r\n" +
                     "details: {0}", jobDetails);

            await DeleteJobFromQueueAsync(jobDetails).ConfigureAwait(false);

            Log.Verbose("Job {0} deleted from the queue", jobDetails.JobId);

            TableResult result = await azureTableProvider.RetrieveAsync(
                ScheduledJobEntity.GetPartitionKey(jobDetails.JobType),
                ScheduledJobEntity.GetRowKey(jobDetails.JobId));

            ScheduledJobEntity entity = (ScheduledJobEntity)result.Result;

            if (entity != null)
            {
                entity.LastRunTime = DateTime.UtcNow;
                entity.Count       = entity.Count + 1;
                if (jobDetails.Payload != null)
                {
                    entity.Payload = JsonConvert.SerializeObject(jobDetails.Payload);
                }
                else
                {
                    entity.Payload = null;
                }

                Recurrence scheduledRecurrence = JsonConvert.DeserializeObject <Recurrence>(entity.Recurrence);
                if (entity.Count == scheduledRecurrence.Count)
                {
                    entity.State = Enum.GetName(typeof(ScheduledJobState), ScheduledJobState.Completed);
                    Log.Verbose("Job {0} completed all scheduled runs. Will be marked complete ", jobDetails.JobId);

                    // if we are marking job as complete, delete payload. It unnecessary inflates the job size
                    // and we don't need it.
                    // Max size for each property is 64K !
                    entity.Payload = null;
                }
                else
                {
                    // schedule next recurrence
                    AzureScheduledJobDetails details = jobDetails as AzureScheduledJobDetails;
                    if (details != null)
                    {
                        details.QueueMessage = null;
// TODO : Include StartTime in calculation ... else drift will increase
                        await azureQueueProvider.EnqueueAsync(new CloudQueueMessage(JsonConvert.SerializeObject(details)),
                                                              scheduledRecurrence.ToTimeSpan()).ConfigureAwait(false);

                        Log.Verbose("Job {0} completed {1} runs, scheduling the next due occurrence", jobDetails.JobId, entity.Count);
                    }
                }

                await azureTableProvider.UpdateAsync(entity).ConfigureAwait(false);
            }

            Log.Info("Successfully marked iteration of job {0} as complete", jobDetails.JobId);
        }
        /// <summary>
        /// Get Job Details from Cloud Queue Message
        /// </summary>
        /// <param name="queueMessage">
        /// Cloud Queue Message
        /// </param>
        /// <returns>
        /// Job Details
        /// </returns>
        public static ScheduledJobDetails FromCloudQueueMessage(CloudQueueMessage queueMessage)
        {
            AzureScheduledJobDetails jobDetails = JsonConvert.DeserializeObject <AzureScheduledJobDetails>(queueMessage.AsString);

            jobDetails.QueueMessage = queueMessage;

            return(jobDetails);
        }
Example #3
0
        /// <summary>
        /// Get a job off the queue to process if available
        /// </summary>
        /// <returns>
        /// Details of the job to run, or NULL if none present
        /// </returns>
        public async Task <ScheduledJobDetails> GetJobToProcessAsync()
        {
            // Get message from queue - timeout of 1 min
            CloudQueueMessage message = await azureQueueProvider.DequeueAsync(TimeSpan.FromMinutes(1)).ConfigureAwait(false);

            ScheduledJobDetails details = null;

//TODO: Add logic to log these every _n_ times instead of once per polling interval (currently 50ms).
//            Log.Verbose("Incoming request to get a job to be processed");
            if (message != null)
            {
                // Get entity from table
                details = AzureScheduledJobDetails.FromCloudQueueMessage(message);
                TableResult result = await azureTableProvider.RetrieveAsync(
                    ScheduledJobEntity.GetPartitionKey(details.JobType),
                    ScheduledJobEntity.GetRowKey(details.JobId)).ConfigureAwait(false);

                ScheduledJobEntity entity = (ScheduledJobEntity)result.Result;

                if (entity == null)
                {
                    // something bad happened in scheduling
                    Log.Critical(500, "Deleting Job from queue as entity does not exist , jobId {0} ", details.JobId);
                    await DeleteJobFromQueueAsync(details).ConfigureAwait(false);

                    details = null;
                }
                else
                {
                    int currentVersion = entity.Version;

                    // if version mismatch, that means job has been updated
                    // We should delete the current message from the Queue
                    if (currentVersion != details.Version)
                    {
                        await DeleteJobFromQueueAsync(details).ConfigureAwait(false);

                        details = null;
                    }
                }
            }

            if (details != null)
            {
                Log.Info("Job to be processed retrieved \r\n" +
                         "details : {0}", details);
            }

            return(details);
        }
Example #4
0
        /// <summary>
        /// Use this to increase visibility timeout of a job which might take longer to process
        /// </summary>
        /// <param name="jobDetails">
        /// Job Details
        /// </param>
        /// <param name="newTimeout">
        /// What should be the new timeout
        /// </param>
        /// <returns>
        /// Async Task Wrapper
        /// </returns>
        public async Task IncreaseVisibilityTimeout(ScheduledJobDetails jobDetails, TimeSpan newTimeout)
        {
            if (jobDetails == null)
            {
                throw new SchedulerException("JobDetails cannot be null");
            }

            Log.Info("Updating timeout of job {0} to {1} ", jobDetails.JobId, newTimeout.ToString());
            AzureScheduledJobDetails azureJobDetails = jobDetails as AzureScheduledJobDetails;
            CloudQueueMessage        message         = AzureScheduledJobDetails.ToCloudQueueMessage(azureJobDetails);
            await azureQueueProvider.IncreaseTimeout(message, newTimeout).ConfigureAwait(false);

            Log.Info("Successfully updated timeout of job {0} ", jobDetails.JobId);
        }
Example #5
0
        /// <summary>
        /// Update the job payload to the new payload specified
        /// </summary>
        /// <param name="jobDetails">
        /// Details of the job to be updated
        /// </param>
        /// <returns>
        /// Task wrapper for async operation
        /// </returns>
        /// <remarks>
        /// This update is done in place, hence queue order is not changed.
        /// Please be aware that this call only updates the payload.
        /// Imp : NOT THREADSAFE. So multiple calls can arrive out of order
        /// to make payload be off sync. Be careful if you have to use it.
        /// </remarks>
        public async Task UpdateJobPayload(ScheduledJobDetails jobDetails)
        {
            if (jobDetails == null)
            {
                throw new SchedulerException("JobDetails cannot be null");
            }

            string errorMessage;

            if (!jobDetails.ValidateUpdate(out errorMessage))
            {
                throw new SchedulerException(errorMessage);
            }

            Log.Info("Incoming request to update payload of a job \r\n" +
                     "details: {0}", jobDetails);

            TableResult result = await azureTableProvider.RetrieveAsync(
                ScheduledJobEntity.GetPartitionKey(jobDetails.JobType),
                ScheduledJobEntity.GetRowKey(jobDetails.JobId)).ConfigureAwait(false);

            ScheduledJobEntity entity = (ScheduledJobEntity)result.Result;

            if (entity != null)
            {
                entity.Payload = JsonConvert.SerializeObject(jobDetails.Payload);
                await azureTableProvider.UpdateAsync(entity).ConfigureAwait(false);

                AzureScheduledJobDetails azureJobDetails = jobDetails as AzureScheduledJobDetails;
                CloudQueueMessage        message         = AzureScheduledJobDetails.ToCloudQueueMessage(azureJobDetails);
                // azureJobDetails.QueueMessage = null;
                message.SetMessageContent(JsonConvert.SerializeObject(jobDetails));
                await azureQueueProvider.UpdateAsync(message).ConfigureAwait(false);
            }

            Log.Info("Successfully updated payload of job {0} ", jobDetails.JobId);
        }
 /// <summary>
 /// Convert Job Details to Cloud Queue Message
 /// </summary>
 /// <param name="azureScheduledJobDetails">
 /// Job Details
 /// </param>
 /// <returns>
 /// Cloud Queue Message
 /// </returns>
 public static CloudQueueMessage ToCloudQueueMessage(AzureScheduledJobDetails azureScheduledJobDetails)
 {
     return(azureScheduledJobDetails.QueueMessage);
 }
Example #7
0
 /// <summary>
 /// Delete job from the queue
 /// </summary>
 /// <param name="jobDetails">
 /// Job Details
 /// </param>
 /// <returns>
 /// Task wrapper for async operations
 /// </returns>
 private async Task DeleteJobFromQueueAsync(ScheduledJobDetails jobDetails)
 {
     await azureQueueProvider.DeleteAsync(
         AzureScheduledJobDetails.ToCloudQueueMessage((AzureScheduledJobDetails)jobDetails)).ConfigureAwait(false);
 }