public void Test_CanNotifyTaskErrored()
        {
            Faker faker = new Faker();

            Mock <IQueuedTaskToken> taskMock =
                new Mock <IQueuedTaskToken>(MockBehavior.Loose);

            using (CancellationTokenSource cts = new CancellationTokenSource())
            {
                Exception exc           = faker.System.Exception();
                bool      isRecoverable = faker.Random.Bool();

                TaskExecutionContext ctx = new TaskExecutionContext(taskMock.Object, cts.Token);

                ctx.NotifyTaskErrored(new QueuedTaskError(exc), isRecoverable);

                Assert.IsTrue(ctx.HasResult);
                Assert.NotNull(ctx.ResultInfo);
                Assert.IsFalse(ctx.ResultInfo.ExecutedSuccessfully);
                Assert.IsFalse(ctx.ResultInfo.ExecutionCancelled);

                Assert.NotNull(ctx.ResultInfo.Error);
                Assert.AreEqual(exc.GetType().FullName, ctx.ResultInfo.Error.Type);
                Assert.AreEqual(exc.Message, ctx.ResultInfo.Error.Message);
                Assert.AreEqual(exc.StackTrace, ctx.ResultInfo.Error.StackTrace);

                Assert.AreEqual(isRecoverable, ctx.ResultInfo.IsRecoverable);

                Assert.IsFalse(ctx.IsCancellationRequested);
            }
        }
示例#2
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;
		}