Example #1
0
    protected async override Task ExecuteAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Job service is starting.");

        bool started = false;

        while (!cancellationToken.IsCancellationRequested)
        {
            using (var serviceScope = _services.CreateScope())
            {
                var               scopeServiceProvider = serviceScope.ServiceProvider;
                IJobStore         jobStore             = scopeServiceProvider.GetRequiredService <IJobStore>();
                IJobServiceEvents jobServiceEvents     = scopeServiceProvider.GetRequiredService <IJobServiceEvents>();

                if (!started)
                {
                    await jobServiceEvents.OnStartedAsync();

                    started = true;
                }

                JobDescriptor?job;
                try
                {
                    job = await jobStore.NextAsync(cancellationToken);

                    if (job == null)
                    {
                        if (!cancellationToken.IsCancellationRequested)
                        {
                            throw new Exception("Job store returned null for next job with no cancellation");
                        }

                        break;
                    }
                }
                catch (TaskCanceledException ex)
                {
                    _logger.LogInformation(ex, "The service was stopped while waiting for a job");
                    await jobServiceEvents.OnStoppedAsync();

                    break;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "An error occurred while waiting for a job");
                    await jobServiceEvents.OnFailedAsync(ex);

                    break;
                }

                try
                {
                    var jobRunner = new JobRunner(scopeServiceProvider);
                    if (_options.JobTimeout.HasValue)
                    {
                        var timeoutCts = new CancellationTokenSource(_options.JobTimeout.Value);
                        using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token))
                        {
                            await jobRunner.RunAsync(job.Call, cancellationToken);

                            if (cancellationToken.IsCancellationRequested)
                            {
                                _logger.LogError($"Job cancelled.");
                                await jobStore.FailedAsync(job.Id, ex : null);
                            }
                            else if (timeoutCts.IsCancellationRequested)
                            {
                                _logger.LogError($"Job timed out.");
                                await jobStore.FailedAsync(job.Id, ex : null);
                            }
                            else
                            {
                                await jobStore.SucceededAsync(job.Id);
                            }
                        }
                    }
                    else
                    {
                        await jobRunner.RunAsync(job.Call, cancellationToken);

                        await jobStore.SucceededAsync(job.Id);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"An error occurred while executing job ID '{job.Id}'");

                    await jobStore.FailedAsync(job.Id, ex);

                    await jobServiceEvents.OnFailedAsync(ex);
                }
            }
        }

        _logger.LogInformation("Job service is stopping.");
    }