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); } }
public Task <InvocationResult> InvokeContinuation(InvocationContext context) { InvocationResult result = BindContext(context); if (result != null) { return(Task.FromResult(result)); } return(InvokeCore(() => Resume())); }
protected internal override async Task <InvocationResult> Invoke() { try { await Execute(); return(InvocationResult.Completed()); } catch (Exception ex) { return(InvocationResult.Faulted(ex)); } }
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)); } }
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)); } }
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); }
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); }
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())); }
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())); }
private Task <InvocationState> EnqueueRepeat(InvocationState repeat, InvocationResult result) { return(Queue.Enqueue(repeat.Job, Constants.Source_RepeatingJob, repeat.Payload, result.RescheduleIn.Value)); }
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); } } }
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); } } }