From d5acde4186e73ad73488329edf36aa42c7759706 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Mon, 18 Dec 2017 00:40:20 +0100 Subject: [PATCH] 1) Do not enqueue events twice 2) Fixed style for rule events. --- .../Rules/RuleJob.cs | 2 +- .../HandleRules/Constants.cs | 17 +++++++++ .../HandleRules/RuleService.cs | 13 +++++-- .../Rules/MongoRuleEventEntity.cs | 2 +- .../Rules/MongoRuleEventRepository.cs | 8 ++-- .../Rules/RuleEnqueuer.cs | 9 ++--- .../EventSourcing/JsonEventDataFormatter.cs | 2 + .../events/rule-events-page.component.scss | 4 +- .../HandleRules/RuleServiceTests.cs | 37 ++++++++++++++++++- .../Rules/RuleDequeuerTests.cs | 2 +- 10 files changed, 77 insertions(+), 19 deletions(-) create mode 100644 src/Squidex.Domain.Apps.Core.Operations/HandleRules/Constants.cs diff --git a/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs b/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs index 3117fd8e2..efb38f5ac 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Core.Rules { public sealed class RuleJob { - public Guid RuleId { get; set; } + public Guid JobId { get; set; } public Guid AppId { get; set; } diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Constants.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Constants.cs new file mode 100644 index 000000000..f271312bc --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/Constants.cs @@ -0,0 +1,17 @@ +// ========================================================================== +// Constants.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using NodaTime; + +namespace Squidex.Domain.Apps.Core.HandleRules +{ + public static class Constants + { + public static readonly Duration ExpirationTime = Duration.FromDays(2); + } +} diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs index 79ad0a013..14cb4b2b6 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs @@ -23,7 +23,6 @@ namespace Squidex.Domain.Apps.Core.HandleRules public class RuleService { private const string ContentPrefix = "Content"; - private static readonly Duration ExpirationTime = Duration.FromDays(2); private readonly Dictionary ruleActionHandlers; private readonly Dictionary ruleTriggerHandlers; private readonly TypeNameRegistry typeNameRegistry; @@ -84,18 +83,26 @@ namespace Squidex.Domain.Apps.Core.HandleRules var actionName = typeNameRegistry.GetName(actionType); var actionData = actionHandler.CreateJob(appEventEnvelope, eventName, rule.Action); + var eventTime = @event.Headers.Contains(CommonHeaders.Timestamp) ? @event.Headers.Timestamp() : now; + var eventGuid = @event.Headers.Contains(CommonHeaders.EventId) ? @event.Headers.EventId() : Guid.NewGuid(); + var job = new RuleJob { - RuleId = Guid.NewGuid(), + JobId = eventGuid, ActionName = actionName, ActionData = actionData.Data, AppId = appEvent.AppId.Id, Created = now, EventName = eventName, - Expires = now.Plus(ExpirationTime), + Expires = eventTime.Plus(Constants.ExpirationTime), Description = actionData.Description }; + if (job.Expires < now) + { + return null; + } + return job; } diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs index f57382d6e..daa238708 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules { [BsonRequired] [BsonElement] - public Guid AssetId { get; set; } + public Guid AppId { get; set; } [BsonRequired] [BsonElement] diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs index 73c5655f2..0e1e76d2d 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules protected override async Task SetupCollectionAsync(IMongoCollection collection) { await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.NextAttempt)); - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AssetId).Descending(x => x.Created)); + await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId).Descending(x => x.Created)); await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.Expires), new CreateIndexOptions { ExpireAfter = TimeSpan.Zero }); } @@ -48,7 +48,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules public async Task> QueryByAppAsync(Guid appId, int skip = 0, int take = 20) { var ruleEventEntities = - await Collection.Find(x => x.AssetId == appId).Skip(skip).Limit(take).SortByDescending(x => x.Created) + await Collection.Find(x => x.AppId == appId).Skip(skip).Limit(take).SortByDescending(x => x.Created) .ToListAsync(); return ruleEventEntities; @@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules public async Task CountByAppAsync(Guid appId) { - return (int)await Collection.CountAsync(x => x.AssetId == appId); + return (int)await Collection.CountAsync(x => x.AppId == appId); } public Task EnqueueAsync(Guid id, Instant nextAttempt) @@ -75,7 +75,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules public Task EnqueueAsync(RuleJob job, Instant nextAttempt) { - var entity = SimpleMapper.Map(job, new MongoRuleEventEntity { Job = job, Created = nextAttempt, NextAttempt = nextAttempt }); + var entity = SimpleMapper.Map(job, new MongoRuleEventEntity { Id = job.JobId, Job = job, Created = nextAttempt, NextAttempt = nextAttempt }); return Collection.InsertOneIfNotExistsAsync(entity); } diff --git a/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs b/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs index d3fcbf959..90fe5c1d5 100644 --- a/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs +++ b/src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs @@ -7,6 +7,7 @@ // ========================================================================== using System.Threading.Tasks; +using NodaTime; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Entities.Rules.Repositories; using Squidex.Domain.Apps.Events; @@ -32,19 +33,17 @@ namespace Squidex.Domain.Apps.Entities.Rules get { return ".*"; } } - public RuleEnqueuer( - IRuleEventRepository ruleEventRepository, IAppProvider appProvider, + public RuleEnqueuer(IAppProvider appProvider, IRuleEventRepository ruleEventRepository, RuleService ruleService) { + Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(ruleEventRepository, nameof(ruleEventRepository)); Guard.NotNull(ruleService, nameof(ruleService)); - Guard.NotNull(appProvider, nameof(appProvider)); + this.appProvider = appProvider; this.ruleEventRepository = ruleEventRepository; this.ruleService = ruleService; - - this.appProvider = appProvider; } public Task ClearAsync() diff --git a/src/Squidex.Infrastructure/EventSourcing/JsonEventDataFormatter.cs b/src/Squidex.Infrastructure/EventSourcing/JsonEventDataFormatter.cs index d3c7b6d7d..249d91f96 100644 --- a/src/Squidex.Infrastructure/EventSourcing/JsonEventDataFormatter.cs +++ b/src/Squidex.Infrastructure/EventSourcing/JsonEventDataFormatter.cs @@ -39,6 +39,8 @@ namespace Squidex.Infrastructure.EventSourcing var envelope = new Envelope(eventPayload, headers); + envelope.SetEventId(eventData.EventId); + return envelope; } diff --git a/src/Squidex/app/features/rules/pages/events/rule-events-page.component.scss b/src/Squidex/app/features/rules/pages/events/rule-events-page.component.scss index bc650f4f1..b085f19da 100644 --- a/src/Squidex/app/features/rules/pages/events/rule-events-page.component.scss +++ b/src/Squidex/app/features/rules/pages/events/rule-events-page.component.scss @@ -29,13 +29,13 @@ h3 { position: relative; background: $color-border; border: 0; - margin: -1.25rem; + margin: -.7rem -1.25rem; margin-bottom: 1rem; } &::before { @include caret-top($color-border); - @include absolute(-1.1rem, 2.3rem, auto, auto); + @include absolute(-1.1rem, 2.5rem, auto, auto); } h3 { diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs index 5431f178a..ba4d19703 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs @@ -114,7 +114,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules } [Fact] - public void Should_create_job_if_triggeres() + public void Should_not_create_job_if_too_old() { var e = new ContentCreated { SchemaId = new NamedId(Guid.NewGuid(), "my-schema"), AppId = new NamedId(Guid.NewGuid(), "my-event") }; @@ -123,6 +123,39 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction()); var ruleEnvelope = Envelope.Create(e); + ruleEnvelope.SetTimestamp(now.Minus(Duration.FromDays(3))); + + var actionData = new RuleJobData(); + var actionDescription = "MyDescription"; + + var eventName = "MySchemaCreatedEvent"; + + A.CallTo(() => clock.GetCurrentInstant()) + .Returns(now); + + A.CallTo(() => ruleTriggerHandler.Triggers(A>.Ignored, ruleConfig.Trigger)) + .Returns(true); + + A.CallTo(() => ruleActionHandler.CreateJob(A>.Ignored, eventName, ruleConfig.Action)) + .Returns((actionDescription, actionData)); + + var job = sut.CreateJob(ruleConfig, ruleEnvelope); + + Assert.Null(job); + } + + [Fact] + public void Should_create_job_if_triggered() + { + var e = new ContentCreated { SchemaId = new NamedId(Guid.NewGuid(), "my-schema"), AppId = new NamedId(Guid.NewGuid(), "my-event") }; + + var now = SystemClock.Instance.GetCurrentInstant(); + + var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction()); + var ruleEnvelope = Envelope.Create(e); + + ruleEnvelope.SetTimestamp(now); + var actionName = "WebhookAction"; var actionData = new RuleJobData(); var actionDescription = "MyDescription"; @@ -151,7 +184,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules Assert.Equal(e.AppId.Id, job.AppId); - Assert.NotEqual(Guid.Empty, job.RuleId); + Assert.NotEqual(Guid.Empty, job.JobId); } [Fact] diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs index 3737294be..327d9055a 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs @@ -82,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Rules var job = new RuleJob { - RuleId = Guid.NewGuid(), + JobId = Guid.NewGuid(), ActionData = actionData, ActionName = actionName, Created = now