public async IAsyncEnumerable <JobResult> CreateSnapshotJobsAsync(RuleContext context, [EnumeratorCancellation] CancellationToken ct = default) { Guard.NotNull(context.Rule, nameof(context.Rule)); var rule = context.Rule; if (!rule.IsEnabled) { yield break; } if (!ruleTriggerHandlers.TryGetValue(rule.Trigger.GetType(), out var triggerHandler)) { yield break; } if (!ruleActionHandlers.TryGetValue(rule.Action.GetType(), out var actionHandler)) { yield break; } if (!triggerHandler.CanCreateSnapshotEvents) { yield break; } var now = clock.GetCurrentInstant(); await foreach (var enrichedEvent in triggerHandler.CreateSnapshotEventsAsync(context, ct)) { JobResult?job; try { await eventEnricher.EnrichAsync(enrichedEvent, null); if (!triggerHandler.Trigger(enrichedEvent, context)) { continue; } job = await CreateJobAsync(actionHandler, enrichedEvent, context, now); } catch (Exception ex) { job = new JobResult(null, ex); } yield return(job); } }
public async IAsyncEnumerable <(RuleJob?Job, Exception?Exception)> CreateSnapshotJobsAsync(Rule rule, DomainId ruleId, DomainId appId) { if (!rule.IsEnabled) { yield break; } if (!ruleTriggerHandlers.TryGetValue(rule.Trigger.GetType(), out var triggerHandler)) { yield break; } if (!ruleActionHandlers.TryGetValue(rule.Action.GetType(), out var actionHandler)) { yield break; } if (!triggerHandler.CanCreateSnapshotEvents) { yield break; } var now = clock.GetCurrentInstant(); await foreach (var enrichedEvent in triggerHandler.CreateSnapshotEvents(rule.Trigger, appId)) { Exception?exception; RuleJob?job = null; try { await eventEnricher.EnrichAsync(enrichedEvent, null); if (!triggerHandler.Trigger(enrichedEvent, rule.Trigger)) { continue; } (job, exception) = await CreateJobAsync(rule, ruleId, actionHandler, now, enrichedEvent); } catch (Exception ex) { exception = ex; } yield return(job, exception); } }
public RuleServiceTests() { typeNameRegistry.Map(typeof(ContentCreated)); typeNameRegistry.Map(typeof(WebhookAction)); A.CallTo(() => eventEnricher.EnrichAsync(A <Envelope <AppEvent> > .Ignored)) .Returns(new EnrichedContentEvent()); A.CallTo(() => ruleActionHandler.ActionType) .Returns(typeof(WebhookAction)); A.CallTo(() => ruleTriggerHandler.TriggerType) .Returns(typeof(ContentChangedTrigger)); sut = new RuleService(new[] { ruleTriggerHandler }, new[] { ruleActionHandler }, eventEnricher, clock, typeNameRegistry); }
public async Task Should_create_job_if_triggered() { var now = clock.GetCurrentInstant(); var rule = ValidRule(); var enrichedEvent = new EnrichedContentEvent { AppId = appId }; var @event = Envelope.Create(new ContentCreated()).SetTimestamp(now); A.CallTo(() => ruleTriggerHandler.Trigger(@event.Payload, rule.Trigger, ruleId)) .Returns(true); A.CallTo(() => ruleTriggerHandler.Trigger(enrichedEvent, rule.Trigger)) .Returns(true); A.CallTo(() => ruleTriggerHandler.CreateEnrichedEventAsync(A <Envelope <AppEvent> > .That.Matches(x => x.Payload == @event.Payload))) .Returns(enrichedEvent); A.CallTo(() => ruleActionHandler.CreateJobAsync(A <EnrichedEvent> .Ignored, rule.Action)) .Returns((actionDescription, new ValidData { Value = 10 })); var job = await sut.CreateJobAsync(rule, ruleId, @event); Assert.Equal(actionData, job.ActionData); Assert.Equal(actionName, job.ActionName); Assert.Equal(actionDescription, job.Description); Assert.Equal(now, job.Created); Assert.Equal(now.Plus(Duration.FromDays(2)), job.Expires); Assert.Equal(enrichedEvent.AppId.Id, job.AppId); Assert.NotEqual(Guid.Empty, job.JobId); A.CallTo(() => eventEnricher.EnrichAsync(enrichedEvent, A <Envelope <AppEvent> > .That.Matches(x => x.Payload == @event.Payload))) .MustHaveHappened(); }
public virtual async Task <RuleJob> CreateJobAsync(Rule rule, Envelope <IEvent> @event) { Guard.NotNull(rule, nameof(rule)); Guard.NotNull(@event, nameof(@event)); if (!rule.IsEnabled) { return(null); } if (!(@event.Payload is AppEvent appEvent)) { return(null); } var actionType = rule.Action.GetType(); if (!ruleTriggerHandlers.TryGetValue(rule.Trigger.GetType(), out var triggerHandler)) { return(null); } if (!ruleActionHandlers.TryGetValue(actionType, out var actionHandler)) { return(null); } var appEventEnvelope = @event.To <AppEvent>(); if (!triggerHandler.Triggers(appEventEnvelope, rule.Trigger)) { return(null); } var now = clock.GetCurrentInstant(); var eventTime = @event.Headers.ContainsKey(CommonHeaders.Timestamp) ? @event.Headers.Timestamp() : now; var expires = eventTime.Plus(Constants.ExpirationTime); if (expires < now) { return(null); } var enrichedEvent = await eventEnricher.EnrichAsync(appEventEnvelope); var actionName = typeNameRegistry.GetName(actionType); var actionData = await actionHandler.CreateJobAsync(enrichedEvent, rule.Action); var json = jsonSerializer.Serialize(actionData.Data); var job = new RuleJob { JobId = Guid.NewGuid(), ActionName = actionName, ActionData = json, AggregateId = enrichedEvent.AggregateId, AppId = appEvent.AppId.Id, Created = now, EventName = enrichedEvent.Name, Expires = expires, Description = actionData.Description }; return(job); }
public virtual async Task <RuleJob> CreateJobAsync(Rule rule, Guid ruleId, Envelope <IEvent> @event) { Guard.NotNull(rule, nameof(rule)); Guard.NotNull(@event, nameof(@event)); try { if (!rule.IsEnabled) { return(null); } if (!(@event.Payload is AppEvent)) { return(null); } var typed = @event.To <AppEvent>(); var actionType = rule.Action.GetType(); if (!ruleTriggerHandlers.TryGetValue(rule.Trigger.GetType(), out var triggerHandler)) { return(null); } if (!ruleActionHandlers.TryGetValue(actionType, out var actionHandler)) { return(null); } var now = clock.GetCurrentInstant(); var eventTime = @event.Headers.ContainsKey(CommonHeaders.Timestamp) ? @event.Headers.Timestamp() : now; var expires = eventTime.Plus(Constants.ExpirationTime); if (expires < now) { return(null); } if (!triggerHandler.Trigger(typed.Payload, rule.Trigger, ruleId)) { return(null); } var appEventEnvelope = @event.To <AppEvent>(); var enrichedEvent = await triggerHandler.CreateEnrichedEventAsync(appEventEnvelope); if (enrichedEvent == null) { return(null); } await eventEnricher.EnrichAsync(enrichedEvent, typed); if (!triggerHandler.Trigger(enrichedEvent, rule.Trigger)) { return(null); } var actionName = typeNameRegistry.GetName(actionType); var actionData = await actionHandler.CreateJobAsync(enrichedEvent, rule.Action); var json = jsonSerializer.Serialize(actionData.Data); var job = new RuleJob { JobId = Guid.NewGuid(), ActionName = actionName, ActionData = json, AppId = enrichedEvent.AppId.Id, Created = now, EventName = enrichedEvent.Name, ExecutionPartition = enrichedEvent.Partition, Expires = expires, Description = actionData.Description }; return(job); } catch (Exception ex) { log.LogError(ex, w => w .WriteProperty("action", "createRuleJob") .WriteProperty("status", "Failed")); return(null); } }
public virtual async Task <JobList> CreateJobsAsync(Rule rule, DomainId ruleId, Envelope <IEvent> @event, bool ignoreStale = true) { Guard.NotNull(rule, nameof(rule)); Guard.NotNull(@event, nameof(@event)); var result = new JobList(); try { if (!rule.IsEnabled) { return(result); } if (!(@event.Payload is AppEvent)) { return(result); } var typed = @event.To <AppEvent>(); if (typed.Payload.FromRule) { return(result); } var actionType = rule.Action.GetType(); if (!ruleTriggerHandlers.TryGetValue(rule.Trigger.GetType(), out var triggerHandler)) { return(result); } if (!ruleActionHandlers.TryGetValue(actionType, out var actionHandler)) { return(result); } var now = clock.GetCurrentInstant(); var eventTime = @event.Headers.ContainsKey(CommonHeaders.Timestamp) ? @event.Headers.Timestamp() : now; if (ignoreStale && eventTime.Plus(Constants.StaleTime) < now) { return(result); } var expires = now.Plus(Constants.ExpirationTime); if (!triggerHandler.Trigger(typed.Payload, rule.Trigger, ruleId)) { return(result); } var appEventEnvelope = @event.To <AppEvent>(); var enrichedEvents = await triggerHandler.CreateEnrichedEventsAsync(appEventEnvelope); foreach (var enrichedEvent in enrichedEvents) { try { await eventEnricher.EnrichAsync(enrichedEvent, typed); if (!triggerHandler.Trigger(enrichedEvent, rule.Trigger)) { continue; } var actionName = typeNameRegistry.GetName(actionType); 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 = ruleId }; try { var(description, data) = await actionHandler.CreateJobAsync(enrichedEvent, rule.Action); var json = jsonSerializer.Serialize(data); job.ActionData = json; job.ActionName = actionName; job.Description = description; result.Add((job, null)); } catch (Exception ex) { job.Description = "Failed to create job"; result.Add((job, ex)); } } catch (Exception ex) { log.LogError(ex, w => w .WriteProperty("action", "createRuleJobFromEvent") .WriteProperty("status", "Failed")); } } } catch (Exception ex) { log.LogError(ex, w => w .WriteProperty("action", "createRuleJob") .WriteProperty("status", "Failed")); } return(result); }