diff --git a/src/Foundatio/Jobs/JobRunner.cs b/src/Foundatio/Jobs/JobRunner.cs index 8554cf70c..31b615af8 100644 --- a/src/Foundatio/Jobs/JobRunner.cs +++ b/src/Foundatio/Jobs/JobRunner.cs @@ -108,33 +108,53 @@ public async Task RunAsync(CancellationToken cancellationToken = default) if (_logger.IsEnabled(LogLevel.Information)) _logger.LogInformation("Starting job type {JobName} on machine {MachineName}...", _jobName, Environment.MachineName); - if (_options.InitialDelay.HasValue && _options.InitialDelay.Value > TimeSpan.Zero) - await SystemClock.SleepAsync(_options.InitialDelay.Value, cancellationToken).AnyContext(); - - if (_options.RunContinuous && _options.InstanceCount > 1) { - var tasks = new List(_options.InstanceCount); - for (int i = 0; i < _options.InstanceCount; i++) { - tasks.Add(Task.Run(async () => { - try { - var jobInstance = _options.JobFactory(); - await jobInstance.RunContinuousAsync(_options.Interval, _options.IterationLimit, cancellationToken).AnyContext(); - } catch (TaskCanceledException) { - } catch (Exception ex) { - if (_logger.IsEnabled(LogLevel.Error)) - _logger.LogError(ex, "Error running job instance: {Message}", ex.Message); - throw; - } - }, cancellationToken)); - } - - await Task.WhenAll(tasks).AnyContext(); - } else if (_options.RunContinuous && _options.InstanceCount == 1) { - await job.RunContinuousAsync(_options.Interval, _options.IterationLimit, cancellationToken).AnyContext(); - } else { - var result = await job.TryRunAsync(cancellationToken).AnyContext(); - _logger.LogJobResult(result, _jobName); + var jobLifetime = job as IAsyncLifetime; + if (jobLifetime != null) { + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("Initializing job lifetime {JobName} on machine {MachineName}...", _jobName, Environment.MachineName); + await jobLifetime.InitializeAsync().AnyContext(); + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("Done initializing job lifetime {JobName} on machine {MachineName}.", _jobName, Environment.MachineName); + } - return result.IsSuccess; + try { + if (_options.InitialDelay.HasValue && _options.InitialDelay.Value > TimeSpan.Zero) + await SystemClock.SleepAsync(_options.InitialDelay.Value, cancellationToken).AnyContext(); + + if (_options.RunContinuous && _options.InstanceCount > 1) { + var tasks = new List(_options.InstanceCount); + for (int i = 0; i < _options.InstanceCount; i++) { + tasks.Add(Task.Run(async () => { + try { + var jobInstance = _options.JobFactory(); + await jobInstance.RunContinuousAsync(_options.Interval, _options.IterationLimit, cancellationToken).AnyContext(); + } catch (TaskCanceledException) { + } catch (Exception ex) { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(ex, "Error running job instance: {Message}", ex.Message); + throw; + } + }, cancellationToken)); + } + + await Task.WhenAll(tasks).AnyContext(); + } else if (_options.RunContinuous && _options.InstanceCount == 1) { + await job.RunContinuousAsync(_options.Interval, _options.IterationLimit, cancellationToken).AnyContext(); + } else { + var result = await job.TryRunAsync(cancellationToken).AnyContext(); + _logger.LogJobResult(result, _jobName); + + return result.IsSuccess; + } + } finally { + var jobDisposable = job as IAsyncDisposable; + if (jobDisposable != null) { + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("Disposing job lifetime {JobName} on machine {MachineName}...", _jobName, Environment.MachineName); + await jobDisposable.DisposeAsync().AnyContext(); + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("Done disposing job lifetime {JobName} on machine {MachineName}.", _jobName, Environment.MachineName); + } } } diff --git a/src/Foundatio/Utility/IAsyncLifetime.cs b/src/Foundatio/Utility/IAsyncLifetime.cs new file mode 100644 index 000000000..dce9921e2 --- /dev/null +++ b/src/Foundatio/Utility/IAsyncLifetime.cs @@ -0,0 +1,9 @@ +using System; +using System.Runtime.ExceptionServices; +using System.Threading.Tasks; + +namespace Foundatio.Utility { + public interface IAsyncLifetime : IAsyncDisposable { + Task InitializeAsync(); + } +} \ No newline at end of file