Browse Source

1) Do not enqueue events twice

2) Fixed style for rule events.
pull/214/head
Sebastian Stehle 8 years ago
parent
commit
d5acde4186
  1. 2
      src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs
  2. 17
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Constants.cs
  3. 13
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs
  4. 2
      src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs
  5. 8
      src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs
  6. 9
      src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs
  7. 2
      src/Squidex.Infrastructure/EventSourcing/JsonEventDataFormatter.cs
  8. 4
      src/Squidex/app/features/rules/pages/events/rule-events-page.component.scss
  9. 37
      tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs
  10. 2
      tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs

2
src/Squidex.Domain.Apps.Core.Model/Rules/RuleJob.cs

@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Core.Rules
{ {
public sealed class RuleJob public sealed class RuleJob
{ {
public Guid RuleId { get; set; } public Guid JobId { get; set; }
public Guid AppId { get; set; } public Guid AppId { get; set; }

17
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);
}
}

13
src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs

@ -23,7 +23,6 @@ namespace Squidex.Domain.Apps.Core.HandleRules
public class RuleService public class RuleService
{ {
private const string ContentPrefix = "Content"; private const string ContentPrefix = "Content";
private static readonly Duration ExpirationTime = Duration.FromDays(2);
private readonly Dictionary<Type, IRuleActionHandler> ruleActionHandlers; private readonly Dictionary<Type, IRuleActionHandler> ruleActionHandlers;
private readonly Dictionary<Type, IRuleTriggerHandler> ruleTriggerHandlers; private readonly Dictionary<Type, IRuleTriggerHandler> ruleTriggerHandlers;
private readonly TypeNameRegistry typeNameRegistry; private readonly TypeNameRegistry typeNameRegistry;
@ -84,18 +83,26 @@ namespace Squidex.Domain.Apps.Core.HandleRules
var actionName = typeNameRegistry.GetName(actionType); var actionName = typeNameRegistry.GetName(actionType);
var actionData = actionHandler.CreateJob(appEventEnvelope, eventName, rule.Action); 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 var job = new RuleJob
{ {
RuleId = Guid.NewGuid(), JobId = eventGuid,
ActionName = actionName, ActionName = actionName,
ActionData = actionData.Data, ActionData = actionData.Data,
AppId = appEvent.AppId.Id, AppId = appEvent.AppId.Id,
Created = now, Created = now,
EventName = eventName, EventName = eventName,
Expires = now.Plus(ExpirationTime), Expires = eventTime.Plus(Constants.ExpirationTime),
Description = actionData.Description Description = actionData.Description
}; };
if (job.Expires < now)
{
return null;
}
return job; return job;
} }

2
src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventEntity.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
{ {
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public Guid AssetId { get; set; } public Guid AppId { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]

8
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<MongoRuleEventEntity> collection) protected override async Task SetupCollectionAsync(IMongoCollection<MongoRuleEventEntity> collection)
{ {
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.NextAttempt)); 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 }); 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<IReadOnlyList<IRuleEventEntity>> QueryByAppAsync(Guid appId, int skip = 0, int take = 20) public async Task<IReadOnlyList<IRuleEventEntity>> QueryByAppAsync(Guid appId, int skip = 0, int take = 20)
{ {
var ruleEventEntities = 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(); .ToListAsync();
return ruleEventEntities; return ruleEventEntities;
@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
public async Task<int> CountByAppAsync(Guid appId) public async Task<int> 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) 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) 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); return Collection.InsertOneIfNotExistsAsync(entity);
} }

9
src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs

@ -7,6 +7,7 @@
// ========================================================================== // ==========================================================================
using System.Threading.Tasks; using System.Threading.Tasks;
using NodaTime;
using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.HandleRules;
using Squidex.Domain.Apps.Entities.Rules.Repositories; using Squidex.Domain.Apps.Entities.Rules.Repositories;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
@ -32,19 +33,17 @@ namespace Squidex.Domain.Apps.Entities.Rules
get { return ".*"; } get { return ".*"; }
} }
public RuleEnqueuer( public RuleEnqueuer(IAppProvider appProvider, IRuleEventRepository ruleEventRepository,
IRuleEventRepository ruleEventRepository, IAppProvider appProvider,
RuleService ruleService) RuleService ruleService)
{ {
Guard.NotNull(appProvider, nameof(appProvider));
Guard.NotNull(ruleEventRepository, nameof(ruleEventRepository)); Guard.NotNull(ruleEventRepository, nameof(ruleEventRepository));
Guard.NotNull(ruleService, nameof(ruleService)); Guard.NotNull(ruleService, nameof(ruleService));
Guard.NotNull(appProvider, nameof(appProvider)); this.appProvider = appProvider;
this.ruleEventRepository = ruleEventRepository; this.ruleEventRepository = ruleEventRepository;
this.ruleService = ruleService; this.ruleService = ruleService;
this.appProvider = appProvider;
} }
public Task ClearAsync() public Task ClearAsync()

2
src/Squidex.Infrastructure/EventSourcing/JsonEventDataFormatter.cs

@ -39,6 +39,8 @@ namespace Squidex.Infrastructure.EventSourcing
var envelope = new Envelope<IEvent>(eventPayload, headers); var envelope = new Envelope<IEvent>(eventPayload, headers);
envelope.SetEventId(eventData.EventId);
return envelope; return envelope;
} }

4
src/Squidex/app/features/rules/pages/events/rule-events-page.component.scss

@ -29,13 +29,13 @@ h3 {
position: relative; position: relative;
background: $color-border; background: $color-border;
border: 0; border: 0;
margin: -1.25rem; margin: -.7rem -1.25rem;
margin-bottom: 1rem; margin-bottom: 1rem;
} }
&::before { &::before {
@include caret-top($color-border); @include caret-top($color-border);
@include absolute(-1.1rem, 2.3rem, auto, auto); @include absolute(-1.1rem, 2.5rem, auto, auto);
} }
h3 { h3 {

37
tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs

@ -114,7 +114,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
} }
[Fact] [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>(Guid.NewGuid(), "my-schema"), AppId = new NamedId<Guid>(Guid.NewGuid(), "my-event") }; var e = new ContentCreated { SchemaId = new NamedId<Guid>(Guid.NewGuid(), "my-schema"), AppId = new NamedId<Guid>(Guid.NewGuid(), "my-event") };
@ -123,6 +123,39 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction()); var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction());
var ruleEnvelope = Envelope.Create(e); 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<Envelope<AppEvent>>.Ignored, ruleConfig.Trigger))
.Returns(true);
A.CallTo(() => ruleActionHandler.CreateJob(A<Envelope<AppEvent>>.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>(Guid.NewGuid(), "my-schema"), AppId = new NamedId<Guid>(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 actionName = "WebhookAction";
var actionData = new RuleJobData(); var actionData = new RuleJobData();
var actionDescription = "MyDescription"; var actionDescription = "MyDescription";
@ -151,7 +184,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
Assert.Equal(e.AppId.Id, job.AppId); Assert.Equal(e.AppId.Id, job.AppId);
Assert.NotEqual(Guid.Empty, job.RuleId); Assert.NotEqual(Guid.Empty, job.JobId);
} }
[Fact] [Fact]

2
tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerTests.cs

@ -82,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
var job = new RuleJob var job = new RuleJob
{ {
RuleId = Guid.NewGuid(), JobId = Guid.NewGuid(),
ActionData = actionData, ActionData = actionData,
ActionName = actionName, ActionName = actionName,
Created = now Created = now

Loading…
Cancel
Save