Пример #1
0
        private async Task ProcessStatsBatchAsync(IEnumerable <StandardExecutionPerformanceMonitorWriteRequest> currentBatch)
        {
            MonotonicTimestamp startWrite = MonotonicTimestamp
                                            .Now();

            List <TaskPerformanceStats> executionTimeInfoBatch =
                new List <TaskPerformanceStats>();

            try
            {
                foreach (StandardExecutionPerformanceMonitorWriteRequest rq in currentBatch)
                {
                    executionTimeInfoBatch.Add(new TaskPerformanceStats(rq.PayloadType, rq.DurationMilliseconds));
                }

                await mStatsWriter.WriteAsync(executionTimeInfoBatch);

                foreach (StandardExecutionPerformanceMonitorWriteRequest rq in currentBatch)
                {
                    rq.SetCompleted(1);
                }

                IncrementPerfMonWriteCount(MonotonicTimestamp
                                           .Since(startWrite));
            }
            catch (Exception exc)
            {
                foreach (StandardExecutionPerformanceMonitorWriteRequest rq in currentBatch)
                {
                    rq.SetFailed(exc);
                    if (rq.CanBeRetried)
                    {
                        mStatsProcessingQueue.Add(rq);
                    }
                }

                mLogger.Error("Error processing performance stats batch", exc);
            }
        }
Пример #2
0
        private void WaitForNotifications(NpgsqlConnection signalingConn, CancellationToken cancellationToken)
        {
            //At this point, check if cancellation was requested
            //  and exit if so
            cancellationToken.ThrowIfCancellationRequested();
            while (true)
            {
                mLogger.DebugFormat("Waiting for notifications on channel {0}...",
                                    mNewTaskNotificationChannelName);

                //Pass the cancellation token to the WaitAsync
                //  to be able to stop the listener when requested
                try
                {
                    //TODO: timeout should be configurable
                    bool hadNotification = signalingConn.Wait(250);
                    if (!hadNotification)
                    {
                        ProcessListenerTimedOutWhileWaiting();
                        mLogger.Debug("Listener timed out while waiting. Checking stop token and restarting wait...");
                    }
                    else
                    {
                        mLogger.Debug("Task Notification received.");
                    }
                }
                catch (NullReferenceException exc)
                {
                    mLogger.Error("Possible connection failure while waiting", exc);
                    break;
                }

                //At this point a notification has been received:
                //   before the next go-around of WaitAsync,
                //  check if cancellation was requested
                cancellationToken.ThrowIfCancellationRequested();
            }
        }
Пример #3
0
		private async Task<TaskExecutionResult> ExecuteTaskAsync ( TaskExecutionContext executionContext )
		{
			ITaskExecutor taskExecutor = null;
			DateTimeOffset retryAt = DateTimeOffset.UtcNow;

			IQueuedTask dequeuedTask = executionContext
				.TaskToken
				.DequeuedTask;

			try
			{
				//Check for cancellation before we start execution
				executionContext.StartTimingExecution();
				executionContext.ThrowIfCancellationRequested();

				//Attempt to resolve and run task executor
				if ( ( taskExecutor = ResolveTaskExecutor( dequeuedTask ) ) != null )
				{
					mLogger.DebugFormat( "Beginning task execution. Task id = {0}.",
						dequeuedTask.Id );

					//Execute task
					await taskExecutor.ExecuteAsync( dequeuedTask.Payload,
						executionContext );

					mLogger.DebugFormat( "Task execution completed. Task id = {0}.",
						dequeuedTask.Id );

					//Ensure we have a result - since no exception was thrown 
					//	and no result explicitly set, assume success.
					if ( !executionContext.HasResult )
						executionContext.NotifyTaskCompleted();
				}
			}
			catch ( OperationCanceledException )
			{
				//User code has observed cancellation request 
				executionContext?.NotifyCancellationObserved();
			}
			catch ( Exception exc )
			{
				mLogger.Error( "Error executing queued task",
					exception: exc );

				bool isRecoverable = mOptions.IsTaskErrorRecoverable( dequeuedTask,
					exc );

				executionContext?.NotifyTaskErrored( new QueuedTaskError( exc ),
					isRecoverable: isRecoverable );
			}
			finally
			{
				executionContext.StopTimingExecution();
			}

			//Compute the amount of time to delay task execution
			//	if execution failed
			if ( executionContext.HasResult
				&& executionContext.ExecutionFailed )
				retryAt = ComputeRetryAt( executionContext.TaskToken );

			return taskExecutor != null
				? new TaskExecutionResult( executionContext.ResultInfo,
					duration: executionContext.Duration,
					retryAt: retryAt,
					faultErrorThresholdCount: mOptions.FaultErrorThresholdCount )
				: null;
		}
Пример #4
0
        private async Task ProcessResultBatchAsync(Queue <PostgreSqlTaskResultQueueProcessRequest> currentBatch)
        {
            MonotonicTimestamp startWrite = MonotonicTimestamp
                                            .Now();

            //An explicit choice has been made not to use transactions
            //	since failing to update a result MUST NOT
            //	cause the other successful updates to be rolled back.
            using (NpgsqlConnection conn = await OpenConnectionAsync(CancellationToken.None))
                using (NpgsqlCommand updateCmd = new NpgsqlCommand(mUpdateSql, conn))
                {
                    NpgsqlParameter pStatus = updateCmd.Parameters
                                              .Add("t_status", NpgsqlDbType.Integer);
                    NpgsqlParameter pLastError = updateCmd.Parameters
                                                 .Add("t_last_error", NpgsqlDbType.Text);
                    NpgsqlParameter pErrorCount = updateCmd.Parameters
                                                  .Add("t_error_count", NpgsqlDbType.Integer);
                    NpgsqlParameter pLastErrorIsRecoverable = updateCmd.Parameters
                                                              .Add("t_last_error_recoverable", NpgsqlDbType.Boolean);
                    NpgsqlParameter pProcessingTime = updateCmd.Parameters
                                                      .Add("t_processing_time_milliseconds", NpgsqlDbType.Bigint);
                    NpgsqlParameter pFinalizedAt = updateCmd.Parameters
                                                   .Add("t_processing_finalized_at_ts", NpgsqlDbType.TimestampTz);
                    NpgsqlParameter pId = updateCmd.Parameters
                                          .Add("t_id", NpgsqlDbType.Uuid);

                    await updateCmd.PrepareAsync();

                    while (currentBatch.Count > 0)
                    {
                        PostgreSqlTaskResultQueueProcessRequest processRq =
                            currentBatch.Dequeue();

                        try
                        {
                            pStatus.Value = ( int )processRq.ResultToUpdate.Status;

                            string strLastError = processRq.ResultToUpdate.LastError.ToJson();
                            if (strLastError != null)
                            {
                                pLastError.Value = strLastError;
                            }
                            else
                            {
                                pLastError.Value = DBNull.Value;
                            }

                            pErrorCount.Value             = processRq.ResultToUpdate.ErrorCount;
                            pLastErrorIsRecoverable.Value = processRq.ResultToUpdate.LastErrorIsRecoverable;
                            pProcessingTime.Value         = processRq.ResultToUpdate.ProcessingTimeMilliseconds;

                            if (processRq.ResultToUpdate.ProcessingFinalizedAtTs.HasValue)
                            {
                                pFinalizedAt.Value = processRq.ResultToUpdate.ProcessingFinalizedAtTs;
                            }
                            else
                            {
                                pFinalizedAt.Value = DBNull.Value;
                            }

                            pId.Value = processRq.ResultToUpdate.Id;

                            int affectedRows = await updateCmd.ExecuteNonQueryAsync();

                            processRq.SetCompleted(affectedRows);

                            IncrementResultWriteCount(MonotonicTimestamp
                                                      .Since(startWrite));
                        }
                        catch (OperationCanceledException)
                        {
                            processRq.SetCancelled();
                            throw;
                        }
                        catch (Exception exc)
                        {
                            processRq.SetFailed(exc);
                            if (processRq.CanBeRetried)
                            {
                                mResultProcessingQueue.Add(processRq);
                            }

                            mLogger.Error("Error processing result", exc);
                        }
                    }

                    await conn.CloseAsync();
                }
        }