public virtual async Task <InvocationResult> Dispatch(InvocationContext context)
        {
            JobDescription jobdef;

            if (!_jobMap.TryGetValue(context.Invocation.Job, out jobdef))
            {
                throw new UnknownJobException(context.Invocation.Job);
            }
            _currentJob = jobdef;

            ILifetimeScope scope = null;

            using (scope = _container.BeginLifetimeScope(b =>
            {
                b.RegisterType(jobdef.Implementation).As(jobdef.Implementation);
                b.RegisterInstance(context).As <InvocationContext>();
                b.Register(ctx => scope)
                .As <ILifetimeScope>();
            }))
            {
                var job = (JobHandlerBase)scope.Resolve(jobdef.Implementation);

                Func <Task <InvocationResult> > invocationThunk = () => job.Invoke(context);
                if (context.Invocation.IsContinuation)
                {
                    IAsyncJob asyncJob = job as IAsyncJob;
                    if (asyncJob == null)
                    {
                        // Just going to be caught below, but that's what we want :).
                        throw new InvalidOperationException(String.Format(
                                                                CultureInfo.CurrentCulture,
                                                                Strings.JobDispatcher_AsyncContinuationOfNonAsyncJob,
                                                                jobdef.Name));
                    }
                    invocationThunk = () => asyncJob.InvokeContinuation(context);
                }

                InvocationEventSource.Log.Invoking(jobdef);
                InvocationResult result = null;

                try
                {
                    context.SetJob(jobdef, job);

                    result = await invocationThunk();
                }
                catch (Exception ex)
                {
                    result = InvocationResult.Faulted(ex);
                }
                _currentJob = null;
                _lastJob    = jobdef;
                return(result);
            }
        }
Beispiel #2
0
        public Task <InvocationResult> InvokeContinuation(InvocationContext context)
        {
            InvocationResult result = BindContext(context);

            if (result != null)
            {
                return(Task.FromResult(result));
            }

            return(InvokeCore(() => Resume()));
        }
Beispiel #3
0
        protected internal override async Task <InvocationResult> Invoke()
        {
            try
            {
                await Execute();

                return(InvocationResult.Completed());
            }
            catch (Exception ex)
            {
                return(InvocationResult.Faulted(ex));
            }
        }
Beispiel #4
0
        protected internal override async Task <InvocationResult> Invoke()
        {
            // Invoke the job. When it returns, it means there's no more data to process
            // So go to sleep until the wait period elapses
            try
            {
                await Execute();

                return(InvocationResult.Completed(WaitPeriod));
            }
            catch (Exception ex)
            {
                return(InvocationResult.Faulted(ex, WaitPeriod));
            }
        }
Beispiel #5
0
        private async Task <InvocationResult> InvokeCore(Func <Task <JobContinuation> > invoker)
        {
            try
            {
                var continuation = await invoker();

                if (continuation != null)
                {
                    return(InvocationResult.Suspended(continuation));
                }
                else
                {
                    return(InvocationResult.Completed());
                }
            }
            catch (Exception ex)
            {
                return(InvocationResult.Faulted(ex));
            }
        }
Beispiel #6
0
 protected virtual InvocationResult BindContext(InvocationContext context)
 {
     // Bind invocation information
     Context       = context;
     TempDirectory = Path.Combine(
         Path.GetTempPath(),
         "NuGetService",
         "InvocationTemp",
         context.Invocation.Id.ToString("N").ToLowerInvariant());
     try
     {
         BindProperties(Invocation.Payload);
     }
     catch (Exception ex)
     {
         InvocationEventSource.Log.BindingError(ex);
         return(InvocationResult.Faulted(ex));
     }
     return(null);
 }
            public async Task GivenJobWithName_ItInvokesTheJobAndReturnsTheResult()
            {
                // Arrange
                var host = new TestServiceHost();

                host.Initialize();

                var job = new JobDescription("test", typeof(TestJob));

                var dispatcher = new JobDispatcher(new[] { job }, host.Container);
                var invocation = TestHelpers.CreateInvocation(Guid.NewGuid(), "Test", "test", new Dictionary <string, string>());
                var context    = new InvocationContext(invocation, queue: null);
                var expected   = InvocationResult.Completed();

                TestJob.SetTestResult(expected);

                // Act
                var actual = await dispatcher.Dispatch(context);

                // Assert
                Assert.Same(expected, actual);
            }
Beispiel #8
0
        public virtual async Task <InvocationResult> Invoke(InvocationContext context)
        {
            InvocationResult result = BindContext(context);

            if (result != null)
            {
                return(result);
            }

            // Invoke the job
            try
            {
                result = await Invoke();
            }
            catch (Exception ex)
            {
                result = InvocationResult.Faulted(ex);
            }

            // Return the result
            return(result);
        }
Beispiel #9
0
 private Task<InvocationState> EnqueueRepeat(InvocationState repeat, InvocationResult result)
 {
     return Queue.Enqueue(repeat.Job, Constants.Source_RepeatingJob, repeat.Payload, result.RescheduleIn.Value);
 }
 public static void SetTestResult(InvocationResult value)
 {
     CallContext.LogicalSetData(typeof(TestJob).FullName + "!TestResult", value);
 }
 public Task <InvocationResult> InvokeContinuation(InvocationContext context)
 {
     return(Task.FromResult(InvocationResult.Completed()));
 }
 public static void SetTestResult(InvocationResult value)
 {
     CallContext.LogicalSetData(typeof(TestJob).FullName + "!TestResult", value);
 }
 protected internal override Task <InvocationResult> Invoke()
 {
     return(Task.FromResult(InvocationResult.Faulted(new Exception("Supposed to be invoked as a continuation!"))));
 }
 protected internal override Task <InvocationResult> Invoke()
 {
     return(Task.FromResult(InvocationResult.Completed()));
 }
Beispiel #15
0
 private Task <InvocationState> EnqueueRepeat(InvocationState repeat, InvocationResult result)
 {
     return(Queue.Enqueue(repeat.Job, Constants.Source_RepeatingJob, repeat.Payload, result.RescheduleIn.Value));
 }
Beispiel #16
0
        protected internal virtual async Task Dispatch(InvocationState invocation, InvocationLogCapture capture, CancellationToken cancelToken, bool includeContinuations)
        {
            InvocationContext.SetCurrentInvocationId(invocation.Id);

            if (invocation.IsContinuation)
            {
                InvocationEventSource.Log.Resumed();
            }
            else
            {
                InvocationEventSource.Log.Started();
            }

            // Record that we are executing the job
            if (!await Queue.UpdateStatus(invocation, InvocationStatus.Executing, ExecutionResult.Incomplete))
            {
                InvocationEventSource.Log.Aborted(invocation);
                return;
            }

            // Create the request.Invocation context and start capturing the logs
            await capture.Start();

            var context = new InvocationContext(invocation, Queue, cancelToken, capture);

            InvocationResult result = null;

            try
            {
                result = await Dispatcher.Dispatch(context);

                // TODO: If response.Continuation != null, enqueue continuation
                switch (result.Result)
                {
                case ExecutionResult.Completed:
                    InvocationEventSource.Log.Succeeded(result);
                    break;

                case ExecutionResult.Faulted:
                    InvocationEventSource.Log.Faulted(result);
                    break;

                case ExecutionResult.Incomplete:
                    InvocationEventSource.Log.Suspended(result);
                    break;

                default:
                    InvocationEventSource.Log.UnknownStatus(result);
                    break;
                }

                if (invocation.NextVisibleAt < Clock.UtcNow)
                {
                    InvocationEventSource.Log.InvocationTookTooLong(invocation);
                }
            }
            catch (Exception ex)
            {
                InvocationEventSource.Log.DispatchError(ex);
                result = new InvocationResult(ExecutionResult.Crashed, ex);
            }

            // Stop capturing and set the log url
            string logUrl = null;

            if (capture != null)
            {
                var logUri = await capture.End();

                if (logUri != null)
                {
                    logUrl = logUri.AbsoluteUri;
                }
            }

            if (result.Result != ExecutionResult.Incomplete)
            {
                // If we're not suspended, the invocation has completed
                InvocationEventSource.Log.Ended();
                await Queue.Complete(invocation, result.Result, result.Exception == null?null : result.Exception.ToString(), logUrl);

                // If we've completed and there's a repeat, queue the repeat
                if (result.RescheduleIn != null)
                {
                    // Rescheule it to run again
                    var repeat = await EnqueueRepeat(invocation, result);

                    InvocationEventSource.Log.ScheduledRepeat(invocation, repeat, result.RescheduleIn.Value);
                }
            }
            else
            {
                if (includeContinuations)
                {
                    invocation.Update(new InvocationState.InvocationRow()
                    {
                        Id              = Guid.NewGuid(),
                        Version         = invocation.CurrentVersion + 1,
                        Job             = invocation.Job,
                        Source          = invocation.Id.ToString("N"),
                        Status          = (int)InvocationStatus.Suspended,
                        Result          = (int)ExecutionResult.Incomplete,
                        LastDequeuedAt  = invocation.LastDequeuedAt == null ? (DateTime?)null : invocation.LastDequeuedAt.Value.UtcDateTime,
                        LastSuspendedAt = DateTime.UtcNow,
                        CompletedAt     = null,
                        QueuedAt        = invocation.QueuedAt.UtcDateTime,
                        NextVisibleAt   = invocation.NextVisibleAt.UtcDateTime + DefaultInvisibilityPeriod,
                        UpdatedAt       = invocation.UpdatedAt.UtcDateTime,
                        Payload         = InvocationPayloadSerializer.Serialize(result.Continuation.Parameters),
                        IsContinuation  = true
                    });

                    // Run the continuation inline after waiting
                    await Task.Delay(result.Continuation.WaitPeriod);

                    await Dispatch(invocation, capture, cancelToken, includeContinuations);
                }
                else
                {
                    // Suspend the job until the continuation is ready to run
                    await Queue.Suspend(invocation, result.Continuation.Parameters, result.Continuation.WaitPeriod, logUrl);
                }
            }
        }
Beispiel #17
0
        protected internal virtual async Task Dispatch(InvocationState invocation, InvocationLogCapture capture, CancellationToken cancelToken, bool includeContinuations)
        {
            InvocationContext.SetCurrentInvocationId(invocation.Id);
            
            if (invocation.IsContinuation)
            {
                InvocationEventSource.Log.Resumed();
            }
            else
            {
                InvocationEventSource.Log.Started();
            }
            
            // Record that we are executing the job
            if (!await Queue.UpdateStatus(invocation, InvocationStatus.Executing, ExecutionResult.Incomplete))
            {
                InvocationEventSource.Log.Aborted(invocation);
                return;
            }

            // Create the request.Invocation context and start capturing the logs
            await capture.Start();
            var context = new InvocationContext(invocation, Queue, cancelToken, capture);

            InvocationResult result = null;
            try
            {
                result = await Dispatcher.Dispatch(context);

                // TODO: If response.Continuation != null, enqueue continuation
                switch (result.Result)
                {
                    case ExecutionResult.Completed:
                        InvocationEventSource.Log.Succeeded(result);
                        break;
                    case ExecutionResult.Faulted:
                        InvocationEventSource.Log.Faulted(result);
                        break;
                    case ExecutionResult.Incomplete:
                        InvocationEventSource.Log.Suspended(result);
                        break;
                    default:
                        InvocationEventSource.Log.UnknownStatus(result);
                        break;
                }

                if (invocation.NextVisibleAt < Clock.UtcNow)
                {
                    InvocationEventSource.Log.InvocationTookTooLong(invocation);
                }
            }
            catch (Exception ex)
            {
                InvocationEventSource.Log.DispatchError(ex);
                result = new InvocationResult(ExecutionResult.Crashed, ex);
            }

            // Stop capturing and set the log url
            string logUrl = null;
            if (capture != null)
            {
                var logUri = await capture.End();
                if (logUri != null)
                {
                    logUrl = logUri.AbsoluteUri;
                }
            }

            if (result.Result != ExecutionResult.Incomplete)
            {
                // If we're not suspended, the invocation has completed
                InvocationEventSource.Log.Ended();
                await Queue.Complete(invocation, result.Result, result.Exception == null ? null : result.Exception.ToString(), logUrl);

                // If we've completed and there's a repeat, queue the repeat
                if (result.RescheduleIn != null)
                {
                    // Rescheule it to run again
                    var repeat = await EnqueueRepeat(invocation, result);
                    InvocationEventSource.Log.ScheduledRepeat(invocation, repeat, result.RescheduleIn.Value);
                }
            }
            else
            {
                if (includeContinuations)
                {
                    invocation.Update(new InvocationState.InvocationRow()
                    {
                        Id = Guid.NewGuid(),
                        Version = invocation.CurrentVersion + 1,
                        Job = invocation.Job,
                        Source = invocation.Id.ToString("N"),
                        Status = (int)InvocationStatus.Suspended,
                        Result = (int)ExecutionResult.Incomplete,
                        LastDequeuedAt = invocation.LastDequeuedAt == null ? (DateTime?)null : invocation.LastDequeuedAt.Value.UtcDateTime,
                        LastSuspendedAt = DateTime.UtcNow,
                        CompletedAt = null,
                        QueuedAt = invocation.QueuedAt.UtcDateTime,
                        NextVisibleAt = invocation.NextVisibleAt.UtcDateTime + DefaultInvisibilityPeriod,
                        UpdatedAt = invocation.UpdatedAt.UtcDateTime,
                        Payload = InvocationPayloadSerializer.Serialize(result.Continuation.Parameters),
                        IsContinuation = true
                    });

                    // Run the continuation inline after waiting
                    await Task.Delay(result.Continuation.WaitPeriod);

                    await Dispatch(invocation, capture, cancelToken, includeContinuations);
                }
                else
                {
                    // Suspend the job until the continuation is ready to run
                    await Queue.Suspend(invocation, result.Continuation.Parameters, result.Continuation.WaitPeriod, logUrl);
                }
            }
        }