public Task EnqueueAsync(CronjobExecutionContext task) { if (task == null) { throw new ArgumentNullException(nameof(task)); } _jobQueue.Enqueue(task); _signal.Release(); return(Task.CompletedTask); }
public async Task ExecuteAsync(CronjobExecutionContext executionContext, CancellationToken cancellationToken = default) { _logger.LogInformation("Executing {Cronjob}", executionContext.Cronjob); try { await _executionMonitor.StartedAsync(executionContext).ConfigureAwait(false); await executionContext.Cronjob.ExecuteAsync(cancellationToken); await _executionMonitor.FinishedAsync(executionContext).ConfigureAwait(false); _logger.LogInformation("Finished executing {Cronjob}", executionContext.Cronjob); } catch (Exception e) { await _executionMonitor.FailedAsync(executionContext, e).ConfigureAwait(false); _logger.LogError(e, "Failed to execute {Cronjob}", executionContext.Cronjob); } finally { _logger.LogInformation("Finished {Cronjob}", executionContext.Cronjob); } }
public Task FailedAsync(CronjobExecutionContext cronjobExecutionContext, Exception exception) => Task.CompletedTask;
public Task FinishedAsync(CronjobExecutionContext cronjobExecutionContext) => Task.CompletedTask;
public static IEndpointConventionBuilder MapCronjobWebhook(this IEndpointRouteBuilder endpoints) { var options = endpoints.ServiceProvider.GetRequiredService <IOptions <CronjobsOptions> >().Value; var listEndpointPattern = options.RoutePattern.TrimEnd('/'); var triggerEndpointPattern = $"{options.RoutePattern.TrimEnd('/')}/{{name:required}}"; endpoints.MapGet(listEndpointPattern, context => { var providers = context.RequestServices.GetRequiredService <ICronjobWebhookProvider>(); var payload = JsonSerializer.Serialize( providers.Cronjobs, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase } ); context.Response.ContentType = MediaTypeNames.Application.Json; return(context.Response.WriteAsync(payload)); }); return(endpoints.MapPost(triggerEndpointPattern, async context => { var options = context.RequestServices.GetRequiredService <IOptions <CronjobsOptions> >().Value; if (options.IsAuthenticated) { var authResult = await context.RequestServices .GetRequiredService <IAuthorizationService>() .AuthorizeAsync(context.User, "cronjob"); if (!authResult.Succeeded) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } } if (!(context.GetRouteValue("name") is string cronjobName)) { context.Response.StatusCode = StatusCodes.Status404NotFound; return; } var logger = context.RequestServices.GetRequiredService <ILoggerFactory>().CreateLogger("CronjobWebhook"); if (!context.Request.Headers.TryGetValue("Execution-Id", out var executionId)) { logger.LogInformation("Request to trigger {Cronjob} is denied, because it's missing Execution-Id header", cronjobName); context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } ICronjob cronjob; try { var factory = context.RequestServices.GetRequiredService <ICronjobFactory>(); cronjob = factory.Create(cronjobName); } catch (ApplicationException) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } logger.LogInformation("Received request to trigger {CronjobType}", cronjob.GetType().FullName); // Cronjobs will be executed outside request context, // So we're using endpoints.ServiceProvider, because context.RequestServices is request-scoped. var executionContext = new CronjobExecutionContext(cronjob, executionId); var executorQueue = context.RequestServices.GetRequiredService <ICronjobQueue>(); await executorQueue.EnqueueAsync(executionContext).ConfigureAwait(false); context.Response.StatusCode = StatusCodes.Status202Accepted; })); }