public IJobScheduler UnRegister(JobRegistration registration) { if (registration != null) { this.Options.Registrations.Remove(registration); } return(this); }
public IJobScheduler Register(JobRegistration registration, IJob job) { EnsureArg.IsNotNull(registration, nameof(registration)); EnsureArg.IsNotNullOrEmpty(registration.Cron, nameof(registration.Cron)); EnsureArg.IsNotNull(job, nameof(job)); registration.Key ??= HashAlgorithm.ComputeHash(job); this.logger.LogInformation($"{{LogKey:l}} registration (key={{JobKey:l}}, id={registration.Identifier}, cron={registration.Cron}, isReentrant={registration.IsReentrant}, timeout={registration.Timeout:c}, enabled={registration.Enabled})", LogKeys.JobScheduling, registration.Key); var item = this.Options.Registrations.FirstOrDefault(r => r.Key.Key.SafeEquals(registration.Key)); if (item.Key != null) { this.Options.Registrations.Remove(item.Key); } this.Options.Registrations.Add(registration, job); return(this); }
private async Task ExecuteJobAsync(JobRegistration registration, IJob job, CancellationToken cancellationToken, string[] args = null) { if (registration?.Key.IsNullOrEmpty() == false && job != null) { try { async Task ExecuteAsync() { var correlationId = IdGenerator.Instance.Next; using (var timer = new Foundation.Timer()) using (this.logger.BeginScope(new Dictionary <string, object> { [LogPropertyKeys.CorrelationId] = correlationId })) { // TODO: publish domain event (job started) this.logger.LogJournal(LogKeys.JobScheduling, $"job started: {{JobKey:l}} (id={registration.Identifier}, type={job.GetType().PrettyName()}, isReentrant={registration.IsReentrant}, timeout={registration.Timeout:c})", LogPropertyKeys.TrackStartJob, args: new[] { registration.Key }); //using (var scope = this.tracer?.BuildSpan($"job run {registration.Key}", LogKeys.JobScheduling, SpanKind.Producer).Activate(this.logger)) //{ // current span is somehow not available in created jobs (ServiceProviderJobFactory) try { await job.ExecuteAsync(correlationId, cancellationToken, args).AnyContext(); this.logger.LogJournal(LogKeys.JobScheduling, $"job finished: {{JobKey:l}} (id={registration.Identifier}, type={job.GetType().PrettyName()})", LogPropertyKeys.TrackFinishJob, args: new[] { registration.Key }); } catch (Exception ex) { this.logger.LogError(ex, $"{{LogKey:l}} job failed: {{JobKey:l}} (id={registration.Identifier}, type={job.GetType().PrettyName()}) {ex.GetFullMessage()}", args: new[] { LogKeys.JobScheduling, registration.Key }); } // TODO: publish domain event (job finished) } } if (!registration.IsReentrant) { if (this.mutex.TryAcquireLock(registration.Key)) { try { await ExecuteAsync().AnyContext(); } finally { this.mutex.ReleaseLock(registration.Key); } } else { this.logger.LogWarning($"{{LogKey:l}} already executing (key={{JobKey:l}}, type={job.GetType().PrettyName()})", LogKeys.JobScheduling, registration.Key); } } else { await ExecuteAsync().AnyContext(); } } catch (OperationCanceledException ex) { // TODO: publish domain event (job failed) this.logger.LogWarning(ex, $"{{LogKey:l}} canceled (key={{JobKey:l}}), type={job.GetType().PrettyName()})", LogKeys.JobScheduling, registration.Key); //this.errorHandler?.Invoke(ex); } catch (Exception ex) { // TODO: publish domain event (job failed) this.logger.LogError(ex.InnerException ?? ex, $"{{LogKey:l}} failed (key={{JobKey:l}}), type={job.GetType().PrettyName()})", LogKeys.JobScheduling, registration.Key); this.errorHandler?.Invoke(ex.InnerException ?? ex); } } }