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); } }
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; }