private async Task AddJobsAsync(List <JobResult> jobs, Envelope <IEvent> @event, RuleContext context, CancellationToken ct) { try { var skipReason = SkipReason.None; var rule = context.Rule; if (!rule.IsEnabled) { // For the simulation we want to proceed as much as possible. if (context.IncludeSkipped) { skipReason |= SkipReason.Disabled; } else { jobs.Add(JobResult.Disabled); return; } } if (@event.Payload is not AppEvent) { jobs.Add(JobResult.WrongEvent); return; } var typed = @event.To <AppEvent>(); if (typed.Payload.FromRule) { // For the simulation we want to proceed as much as possible. if (context.IncludeSkipped) { skipReason |= SkipReason.FromRule; } else { jobs.Add(JobResult.FromRule); return; } } var actionType = rule.Action.GetType(); if (!ruleTriggerHandlers.TryGetValue(rule.Trigger.GetType(), out var triggerHandler)) { jobs.Add(JobResult.NoTrigger); return; } if (!triggerHandler.Handles(typed.Payload)) { jobs.Add(JobResult.WrongEventForTrigger); return; } if (!ruleActionHandlers.TryGetValue(actionType, out var actionHandler)) { jobs.Add(JobResult.NoAction); return; } var now = clock.GetCurrentInstant(); var eventTime = @event.Headers.ContainsKey(CommonHeaders.Timestamp) ? @event.Headers.Timestamp() : now; if (!context.IncludeStale && eventTime.Plus(Constants.StaleTime) < now) { // For the simulation we want to proceed as much as possible. if (context.IncludeSkipped) { skipReason |= SkipReason.TooOld; } else { jobs.Add(JobResult.TooOld); return; } } if (!triggerHandler.Trigger(typed, context)) { // For the simulation we want to proceed as much as possible. if (context.IncludeSkipped) { skipReason |= SkipReason.ConditionPrecheckDoesNotMatch; } else { jobs.Add(JobResult.ConditionPrecheckDoesNotMatch); return; } } await foreach (var enrichedEvent in triggerHandler.CreateEnrichedEventsAsync(typed, context, ct)) { if (string.IsNullOrWhiteSpace(enrichedEvent.Name)) { enrichedEvent.Name = GetName(typed.Payload); } try { await eventEnricher.EnrichAsync(enrichedEvent, typed); if (!triggerHandler.Trigger(enrichedEvent, context)) { // For the simulation we want to proceed as much as possible. if (context.IncludeSkipped) { skipReason |= SkipReason.ConditionDoesNotMatch; } else { jobs.Add(JobResult.ConditionDoesNotMatch); return; } } var job = await CreateJobAsync(actionHandler, enrichedEvent, context, now); // If the conditions matchs, we can skip creating a new object and save a few allocation.s if (skipReason != SkipReason.None) { job = job with { SkipReason = skipReason }; } jobs.Add(job); } catch (Exception ex) { if (jobs.Count == 0) { jobs.Add(new JobResult { EnrichedEvent = enrichedEvent, EnrichmentError = ex, SkipReason = SkipReason.Failed }); } log.LogError(ex, w => w .WriteProperty("action", "createRuleJobFromEvent") .WriteProperty("status", "Failed")); } } } catch (Exception ex) { jobs.Add(JobResult.Failed(ex)); log.LogError(ex, w => w .WriteProperty("action", "createRuleJob") .WriteProperty("status", "Failed")); } }
private async Task <JobResult> CreateJobAsync(IRuleActionHandler actionHandler, EnrichedEvent enrichedEvent, RuleContext context, Instant now) { var actionName = typeNameRegistry.GetName(context.Rule.Action.GetType()); var expires = now.Plus(Constants.ExpirationTime); var job = new RuleJob { Id = DomainId.NewGuid(), ActionData = string.Empty, ActionName = actionName, AppId = enrichedEvent.AppId.Id, Created = now, EventName = enrichedEvent.Name, ExecutionPartition = enrichedEvent.Partition, Expires = expires, RuleId = context.RuleId }; try { var(description, data) = await actionHandler.CreateJobAsync(enrichedEvent, context.Rule.Action); var json = jsonSerializer.Serialize(data); job.ActionData = json; job.ActionName = actionName; job.Description = description; return(new JobResult { Job = job, EnrichedEvent = enrichedEvent }); } catch (Exception ex) { job.Description = "Failed to create job"; return(JobResult.Failed(ex, enrichedEvent, job)); } }
public async IAsyncEnumerable <JobResult> CreateJobsAsync(Envelope <IEvent> @event, RuleContext context, [EnumeratorCancellation] CancellationToken ct = default) { Guard.NotNull(@event, nameof(@event)); var jobs = new List <JobResult>(); await AddJobsAsync(jobs, @event, context, ct); foreach (var job in jobs) { if (ct.IsCancellationRequested) { break; } yield return(job); } }