mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
5.1 KiB
144 lines
5.1 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using NodaTime;
|
|
using Orleans;
|
|
using Squidex.Domain.Apps.Core.HandleRules;
|
|
using Squidex.Domain.Apps.Core.Rules;
|
|
using Squidex.Domain.Apps.Core.Rules.Triggers;
|
|
using Squidex.Domain.Apps.Events;
|
|
using Squidex.Infrastructure;
|
|
using Squidex.Infrastructure.EventSourcing;
|
|
|
|
namespace Squidex.Domain.Apps.Entities.Rules.Runner
|
|
{
|
|
public sealed class DefaultRuleRunnerService : IRuleRunnerService
|
|
{
|
|
private const int MaxSimulatedEvents = 100;
|
|
private readonly IEventFormatter eventFormatter;
|
|
private readonly IEventStore eventStore;
|
|
private readonly IGrainFactory grainFactory;
|
|
private readonly IRuleService ruleService;
|
|
|
|
public DefaultRuleRunnerService(IGrainFactory grainFactory,
|
|
IEventFormatter eventFormatter,
|
|
IEventStore eventStore,
|
|
IRuleService ruleService)
|
|
{
|
|
this.grainFactory = grainFactory;
|
|
this.eventFormatter = eventFormatter;
|
|
this.eventStore = eventStore;
|
|
this.ruleService = ruleService;
|
|
}
|
|
|
|
public Task<List<SimulatedRuleEvent>> SimulateAsync(IRuleEntity rule,
|
|
CancellationToken ct = default)
|
|
{
|
|
return SimulateAsync(rule.AppId, rule.Id, rule.RuleDef, ct);
|
|
}
|
|
|
|
public async Task<List<SimulatedRuleEvent>> SimulateAsync(NamedId<DomainId> appId, DomainId ruleId, Rule rule,
|
|
CancellationToken ct = default)
|
|
{
|
|
Guard.NotNull(rule);
|
|
|
|
var context = new RuleContext
|
|
{
|
|
AppId = appId,
|
|
Rule = rule,
|
|
RuleId = ruleId,
|
|
IncludeSkipped = true,
|
|
IncludeStale = true
|
|
};
|
|
|
|
var simulatedEvents = new List<SimulatedRuleEvent>(MaxSimulatedEvents);
|
|
|
|
var fromNow = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromDays(7));
|
|
|
|
await foreach (var storedEvent in eventStore.QueryAllReverseAsync($"^([a-zA-Z0-9]+)\\-{appId.Id}", fromNow, MaxSimulatedEvents, ct))
|
|
{
|
|
var @event = eventFormatter.ParseIfKnown(storedEvent);
|
|
|
|
if (@event?.Payload is AppEvent appEvent)
|
|
{
|
|
// Also create jobs for rules with failing conditions because we want to show them in th table.
|
|
await foreach (var result in ruleService.CreateJobsAsync(@event, context, ct))
|
|
{
|
|
var eventName = result.Job?.EventName;
|
|
|
|
if (string.IsNullOrWhiteSpace(eventName))
|
|
{
|
|
eventName = ruleService.GetName(appEvent);
|
|
}
|
|
|
|
simulatedEvents.Add(new SimulatedRuleEvent
|
|
{
|
|
ActionData = result.Job?.ActionData,
|
|
ActionName = result.Job?.ActionName,
|
|
EnrichedEvent = result.EnrichedEvent,
|
|
Error = result.EnrichmentError?.Message,
|
|
Event = @event.Payload,
|
|
EventId = @event.Headers.EventId(),
|
|
EventName = eventName,
|
|
SkipReason = result.SkipReason
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return simulatedEvents;
|
|
}
|
|
|
|
public bool CanRunRule(IRuleEntity rule)
|
|
{
|
|
var context = GetContext(rule);
|
|
|
|
return context.Rule.IsEnabled && context.Rule.Trigger is not ManualTrigger;
|
|
}
|
|
|
|
public bool CanRunFromSnapshots(IRuleEntity rule)
|
|
{
|
|
var context = GetContext(rule);
|
|
|
|
return CanRunRule(rule) && ruleService.CanCreateSnapshotEvents(context);
|
|
}
|
|
|
|
public Task CancelAsync(DomainId appId,
|
|
CancellationToken ct = default)
|
|
{
|
|
var grain = grainFactory.GetGrain<IRuleRunnerGrain>(appId.ToString());
|
|
|
|
return grain.CancelAsync();
|
|
}
|
|
|
|
public Task<DomainId?> GetRunningRuleIdAsync(DomainId appId,
|
|
CancellationToken ct = default)
|
|
{
|
|
var grain = grainFactory.GetGrain<IRuleRunnerGrain>(appId.ToString());
|
|
|
|
return grain.GetRunningRuleIdAsync();
|
|
}
|
|
|
|
public Task RunAsync(DomainId appId, DomainId ruleId, bool fromSnapshots = false,
|
|
CancellationToken ct = default)
|
|
{
|
|
var grain = grainFactory.GetGrain<IRuleRunnerGrain>(appId.ToString());
|
|
|
|
return grain.RunAsync(ruleId, fromSnapshots);
|
|
}
|
|
|
|
private static RuleContext GetContext(IRuleEntity rule)
|
|
{
|
|
return new RuleContext
|
|
{
|
|
AppId = rule.AppId,
|
|
Rule = rule.RuleDef,
|
|
RuleId = rule.Id
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|