From 0bc062e51488f45718ec415eb6f6f74139f47ae9 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sat, 6 Mar 2021 13:51:29 +0100 Subject: [PATCH] Reduce the number of events. (#664) * Reduce the number of events. * Minor code fix. * Add a few comments. * More comments. * Fix spelling error. * Skip equal test. * Temp. --- .../DomainObject/ContentDomainObject.cs | 145 ++++++++++-------- backend/src/Squidex/appsettings.json | 2 +- 2 files changed, 82 insertions(+), 65 deletions(-) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs index 80c5e3018..bd39483ae 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Linq; using System.Threading.Tasks; using NodaTime; using Squidex.Domain.Apps.Core.Contents; @@ -38,6 +39,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject Capacity = int.MaxValue; } + private Task LoadContext(ContentCommand command, bool optimize) + { + return context.LoadAsync(command.AppId, command.SchemaId, command, optimize); + } + protected override bool IsDeleted() { return Snapshot.IsDeleted; @@ -94,6 +100,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject await CreateCore(c); + // Skip validation for singleton contents because it is published from command middleware. if (context.Schema.SchemaDef.IsSingleton) { ChangeStatus(c.AsChange(Status.Published)); @@ -173,7 +180,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (c.DueTime > SystemClock.Instance.GetCurrentInstant()) { - ScheduleStatus(c, c.DueTime.Value); + ChangeStatusScheduled(c, c.DueTime.Value); } else { @@ -251,78 +258,93 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject { await GuardContent.CanChangeStatus(c, Snapshot, context.Workflow, context.Repository, context.Schema); - if (c.Status != Snapshot.Status) + if (c.Status == Snapshot.Status) { - if (!c.DoNotScript && context.HasScript(c => c.Change)) - { - var change = GetChange(c.Status); + return; + } - var data = Snapshot.Data.Clone(); + // Check for script to skip cloning if no script configured. + if (!c.DoNotScript && context.HasScript(c => c.Change)) + { + var change = GetChange(c.Status); - var newData = await context.ExecuteScriptAndTransformAsync(s => s.Change, - new ScriptVars - { - Operation = change.ToString(), - Data = data, - Status = c.Status, - StatusOld = Snapshot.EditingStatus - }); + // Clone the data, so that we do not change it in cases of errors. + var data = Snapshot.Data.Clone(); - if (!newData.Equals(Snapshot.Data)) + var newData = await context.ExecuteScriptAndTransformAsync(s => s.Change, + new ScriptVars { - Update(c, newData); - } - } + Operation = change.ToString(), + Data = data, + Status = c.Status, + StatusOld = Snapshot.EditingStatus + }); - if (!c.DoNotValidate && c.Status == Status.Published) + // Just update the previous data event to improve performance and add less events. + var previousEvent = + GetUncomittedEvents().Select(x => x.Payload) + .OfType().FirstOrDefault(); + + if (previousEvent != null) + { + previousEvent.Data = newData; + } + else if (!newData.Equals(Snapshot.Data)) { - await context.ValidateOnPublishAsync(Snapshot.Data); + Update(c, newData); } + } - ChangeStatus(c); + if (!c.DoNotValidate && c.Status == Status.Published) + { + await context.ValidateOnPublishAsync(Snapshot.Data); } + + ChangeStatus(c); } - private async Task UpdateCore(UpdateContent c, Func newDataFunc, bool partial) + private async Task UpdateCore(UpdateContent c, Func update, bool partial) { await GuardContent.CanUpdate(c, Snapshot, context.Workflow); - var dataNew = newDataFunc(Snapshot.Data); + var newData = update(Snapshot.Data); - if (!dataNew.Equals(Snapshot.Data)) + if (newData.Equals(Snapshot.Data)) { - if (!c.DoNotValidate) - { - if (partial) - { - await context.ValidateInputPartialAsync(c.Data); - } - else - { - await context.ValidateInputAsync(c.Data); - } - } + return; + } - if (!c.DoNotScript) + if (!c.DoNotValidate) + { + if (partial) { - dataNew = await context.ExecuteScriptAndTransformAsync(s => s.Update, - new ScriptVars - { - Operation = "Update", - Data = dataNew, - DataOld = Snapshot.Data, - Status = Snapshot.EditingStatus, - StatusOld = default - }); + await context.ValidateInputPartialAsync(c.Data); } - - if (!c.DoNotValidate) + else { - await context.ValidateContentAsync(dataNew); + await context.ValidateInputAsync(c.Data); } + } - Update(c, dataNew); + if (!c.DoNotScript) + { + newData = await context.ExecuteScriptAndTransformAsync(s => s.Update, + new ScriptVars + { + Operation = "Update", + Data = newData, + DataOld = Snapshot.Data, + Status = Snapshot.EditingStatus, + StatusOld = default + }); + } + + if (!c.DoNotValidate) + { + await context.ValidateContentAsync(newData); } + + Update(c, newData); } private async Task DeleteCore(DeleteContent c) @@ -361,29 +383,29 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject Raise(command, new ContentStatusChanged { Change = GetChange(command.Status) }); } - private void CreateDraft(CreateContentDraft command, Status status) + private void ChangeStatusScheduled(ChangeContentStatus command, Instant dueTime) { - Raise(command, new ContentDraftCreated { Status = status }); + Raise(command, new ContentStatusScheduled { DueTime = dueTime }); } - private void Delete(DeleteContent command) + private void CancelChangeStatus(ChangeContentStatus command) { - Raise(command, new ContentDeleted()); + Raise(command, new ContentSchedulingCancelled()); } - private void DeleteDraft(DeleteContentDraft command) + private void CreateDraft(CreateContentDraft command, Status status) { - Raise(command, new ContentDraftDeleted()); + Raise(command, new ContentDraftCreated { Status = status }); } - private void CancelChangeStatus(ChangeContentStatus command) + private void Delete(DeleteContent command) { - Raise(command, new ContentSchedulingCancelled()); + Raise(command, new ContentDeleted()); } - private void ScheduleStatus(ChangeContentStatus command, Instant dueTime) + private void DeleteDraft(DeleteContentDraft command) { - Raise(command, new ContentStatusScheduled { DueTime = dueTime }); + Raise(command, new ContentDraftDeleted()); } private void Raise(T command, TEvent @event) where T : class where TEvent : AppEvent @@ -406,10 +428,5 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject return StatusChange.Change; } } - - private Task LoadContext(ContentCommand command, bool optimize) - { - return context.LoadAsync(command.AppId, command.SchemaId, command, optimize); - } } } diff --git a/backend/src/Squidex/appsettings.json b/backend/src/Squidex/appsettings.json index 531bd8291..178d7beb0 100644 --- a/backend/src/Squidex/appsettings.json +++ b/backend/src/Squidex/appsettings.json @@ -175,7 +175,7 @@ "google": { /* - * The Google analtyics id + * The Google analytics ID. */ "analyticsId": "UA-99989790-2" }