diff --git a/src/Squidex.Domain.Apps.Events/Schemas/Utils/SchemaEventDispatcher.cs b/src/Squidex.Domain.Apps.Events/Schemas/Utils/SchemaEventDispatcher.cs index e1b9ccf94..7deea8e63 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/Utils/SchemaEventDispatcher.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/Utils/SchemaEventDispatcher.cs @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Events.Schemas.Utils if (@event.Properties != null) { - schema.Update(@event.Properties); + schema = schema.Update(@event.Properties); } if (@event.Fields != null) @@ -38,20 +38,20 @@ namespace Squidex.Domain.Apps.Events.Schemas.Utils if (eventField.IsHidden) { - field.Hide(); + field = field.Hide(); } if (eventField.IsDisabled) { - field.Disable(); + field = field.Disable(); } if (eventField.IsLocked) { - field.Lock(); + field = field.Lock(); } - schema.AddField(field); + schema = schema.AddField(field); fieldId++; } @@ -67,10 +67,9 @@ namespace Squidex.Domain.Apps.Events.Schemas.Utils Partitioning.Language : Partitioning.Invariant; - var fieldId = @event.FieldId.Id; - var field = registry.CreateField(fieldId, @event.Name, partitioning, @event.Properties); + var field = registry.CreateField(@event.FieldId.Id, @event.Name, partitioning, @event.Properties); - schema = schema.DeleteField(fieldId); + schema = schema.DeleteField(@event.FieldId.Id); schema = schema.AddField(field); return schema; diff --git a/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs b/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs index 5bb383096..139ee1887 100644 --- a/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs +++ b/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs @@ -9,41 +9,38 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Orleans; using Orleans.Concurrency; using Orleans.Runtime; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Read.Apps; using Squidex.Domain.Apps.Read.Rules; using Squidex.Domain.Apps.Read.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.CQRS.Events; +using Squidex.Infrastructure.Orleans; namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations { - public sealed class AppStateGrain : Grain, IAppStateGrain + public sealed class AppStateGrain : GrainV2, IAppStateGrain { private readonly FieldRegistry fieldRegistry; private Exception exception; - public AppStateGrain(FieldRegistry fieldRegistry) + public AppStateGrain(FieldRegistry fieldRegistry, IGrainRuntime runtime) + : base(runtime) { Guard.NotNull(fieldRegistry, nameof(fieldRegistry)); + Guard.NotNull(runtime, nameof(runtime)); this.fieldRegistry = fieldRegistry; } - public override void Participate(IGrainLifecycle lifecycle) - { - lifecycle.Subscribe(GrainLifecycleStage.Activate, ct => OnActivateAsync(), ct => OnDeactivateAsync()); - lifecycle.Subscribe(GrainLifecycleStage.SetupState, ct => LoadStateAsync()); - } - - private async Task LoadStateAsync() + protected override async Task ReadStateAsync() { try { - await this.ReadStateAsync(); + await base.ReadStateAsync(); } catch (Exception ex) { @@ -104,6 +101,18 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations public Task HandleAsync(Immutable> message) { + if (exception != null) + { + if (message.Value.Payload is AppCreated) + { + exception = null; + } + else + { + throw exception; + } + } + State.Apply(message.Value); return WriteStateAsync(); diff --git a/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrainState_Rules.cs b/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrainState_Rules.cs index b96fa76cd..fd6eb9690 100644 --- a/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrainState_Rules.cs +++ b/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrainState_Rules.cs @@ -54,7 +54,7 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations private void UpdateRule(RuleEvent @event, EnvelopeHeaders headers, Action updater = null) { - Rules[@event.RuleId].Clone().Update(@event, headers, updater); + Rules[@event.RuleId] = Rules[@event.RuleId].Clone().Update(@event, headers, updater); } } } diff --git a/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppUserGrain.cs b/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppUserGrain.cs index a474d8f6b..c4cdd146a 100644 --- a/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppUserGrain.cs +++ b/src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppUserGrain.cs @@ -9,12 +9,18 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Orleans; +using Orleans.Runtime; +using Squidex.Infrastructure.Orleans; namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations { - public sealed class AppUserGrain : Grain, IAppUserGrain + public sealed class AppUserGrain : GrainV2, IAppUserGrain { + public AppUserGrain(IGrainRuntime runtime) + : base(runtime) + { + } + public Task AddAppAsync(string appName) { State.AppNames.Add(appName); diff --git a/src/Squidex.Domain.Users/DataProtection/Orleans/Grains/Implementations/XmlRepositoryGrain.cs b/src/Squidex.Domain.Users/DataProtection/Orleans/Grains/Implementations/XmlRepositoryGrain.cs index 370005645..0a104976b 100644 --- a/src/Squidex.Domain.Users/DataProtection/Orleans/Grains/Implementations/XmlRepositoryGrain.cs +++ b/src/Squidex.Domain.Users/DataProtection/Orleans/Grains/Implementations/XmlRepositoryGrain.cs @@ -6,15 +6,40 @@ // All rights reserved. // ========================================================================== +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Orleans; +using Orleans.Runtime; +using Squidex.Infrastructure.Log; +using Squidex.Infrastructure.Orleans; namespace Squidex.Domain.Users.DataProtection.Orleans.Grains.Implementations { - public sealed class XmlRepositoryGrain : Grain>, IXmlRepositoryGrain + public sealed class XmlRepositoryGrain : GrainV2>, IXmlRepositoryGrain { + private readonly ISemanticLog log; + + public XmlRepositoryGrain(IGrainRuntime runtime, ISemanticLog log) + : base(runtime) + { + this.log = log; + } + + protected override async Task ReadStateAsync() + { + try + { + await base.ReadStateAsync(); + } + catch (Exception ex) + { + State = new Dictionary(); + + log.LogError(ex, w => w.WriteProperty("action", "LoadXmlRepository")); + } + } + public Task GetAllElementsAsync() { return Task.FromResult(State.Values.ToArray()); diff --git a/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrain.cs b/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrain.cs index a25690da3..c390bbb54 100644 --- a/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrain.cs +++ b/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrain.cs @@ -13,11 +13,12 @@ using Orleans.Concurrency; using Orleans.Core; using Orleans.Runtime; using Squidex.Infrastructure.Log; +using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Tasks; namespace Squidex.Infrastructure.CQRS.Events.Orleans.Grains.Implementation { - public class EventConsumerGrain : Grain, IEventSubscriber, IEventConsumerGrain + public class EventConsumerGrain : GrainV2, IEventSubscriber, IEventConsumerGrain { private readonly EventDataFormatter eventFormatter; private readonly EventConsumerFactory eventConsumerFactory; @@ -31,8 +32,9 @@ namespace Squidex.Infrastructure.CQRS.Events.Orleans.Grains.Implementation EventDataFormatter eventFormatter, EventConsumerFactory eventConsumerFactory, IEventStore eventStore, - ISemanticLog log) - : this(eventFormatter, eventConsumerFactory, eventStore, log, null, null, null) + ISemanticLog log, + IGrainRuntime runtime) + : this(eventFormatter, eventConsumerFactory, eventStore, log, null, runtime, null) { } @@ -121,7 +123,7 @@ namespace Squidex.Infrastructure.CQRS.Events.Orleans.Grains.Implementation { Unsubscribe(); - State = EventConsumerGrainState.Failed(exception); + State = State.Failed(exception); }); } @@ -216,7 +218,7 @@ namespace Squidex.Infrastructure.CQRS.Events.Orleans.Grains.Implementation .WriteProperty("state", "Failed") .WriteProperty("eventConsumer", eventConsumer.Name)); - State = EventConsumerGrainState.Failed(ex); + State = State.Failed(ex); } await WriteStateAsync(); diff --git a/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrainState.cs b/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrainState.cs index 97bb8ad90..ee12b60b7 100644 --- a/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrainState.cs +++ b/src/Squidex.Infrastructure/CQRS/Events/Orleans/Grains/Implementation/EventConsumerGrainState.cs @@ -29,9 +29,9 @@ namespace Squidex.Infrastructure.CQRS.Events.Orleans.Grains.Implementation return new EventConsumerGrainState { Position = position }; } - public static EventConsumerGrainState Failed(Exception ex) + public EventConsumerGrainState Failed(Exception ex) { - return new EventConsumerGrainState { IsStopped = true, Error = ex?.ToString() }; + return new EventConsumerGrainState { Position = Position, IsStopped = true, Error = ex?.ToString() }; } public EventConsumerGrainState Stopped() diff --git a/src/Squidex.Infrastructure/DomainObjectVersionException.cs b/src/Squidex.Infrastructure/DomainObjectVersionException.cs index 7408f52fe..2d0af3ba6 100644 --- a/src/Squidex.Infrastructure/DomainObjectVersionException.cs +++ b/src/Squidex.Infrastructure/DomainObjectVersionException.cs @@ -7,11 +7,12 @@ // ========================================================================== using System; +using System.Runtime.Serialization; namespace Squidex.Infrastructure { [Serializable] - public sealed class DomainObjectVersionException : DomainObjectException + public class DomainObjectVersionException : DomainObjectException { private readonly long currentVersion; private readonly long expectedVersion; diff --git a/src/Squidex.Infrastructure/Orleans/GrainV2.cs b/src/Squidex.Infrastructure/Orleans/GrainV2.cs new file mode 100644 index 000000000..9099951fb --- /dev/null +++ b/src/Squidex.Infrastructure/Orleans/GrainV2.cs @@ -0,0 +1,83 @@ +// ========================================================================== +// GrainV2.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System.Threading; +using System.Threading.Tasks; +using Orleans; +using Orleans.Core; +using Orleans.Runtime; + +namespace Squidex.Infrastructure.Orleans +{ + public class GrainV2 : Grain where TGrainState : new() + { + private readonly IGrainRuntime runtime; + private IStorage storage; + + protected GrainV2(IGrainRuntime runtime) + { + this.runtime = runtime; + } + + protected GrainV2(IGrainIdentity identity, IGrainRuntime runtime, IStorage storage) + : base(identity, runtime) + { + this.runtime = runtime; + this.storage = storage; + } + + protected TGrainState State + { + get + { + return storage.State; + } + set + { + storage.State = value; + } + } + + protected virtual Task ClearStateAsync() + { + return storage.ClearStateAsync(); + } + + protected virtual Task WriteStateAsync() + { + return storage.WriteStateAsync(); + } + + protected virtual Task ReadStateAsync() + { + return storage.ReadStateAsync(); + } + + public override void Participate(IGrainLifecycle lifecycle) + { + base.Participate(lifecycle); + + lifecycle.Subscribe(GrainLifecycleStage.SetupState, OnSetupState); + } + + private async Task OnSetupState(CancellationToken ct) + { + if (!ct.IsCancellationRequested) + { + storage = runtime.GetStorage(this); + + await OnSetupState(); + } + } + + private async Task OnSetupState() + { + await this.ReadStateAsync(); + } + } +} \ No newline at end of file diff --git a/src/Squidex.Infrastructure/Orleans/OrleansException.cs b/src/Squidex.Infrastructure/Orleans/OrleansException.cs deleted file mode 100644 index d54b3d399..000000000 --- a/src/Squidex.Infrastructure/Orleans/OrleansException.cs +++ /dev/null @@ -1,38 +0,0 @@ -// ========================================================================== -// OrleansException.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Runtime.Serialization; - -namespace Squidex.Infrastructure.Orleans -{ - [Serializable] - public class OrleansException : Exception - { - public OrleansException() - { - } - - public OrleansException(string message) - : base(message) - { - } - - public OrleansException(string message, Exception inner) - : base(message, inner) - { - } - - protected OrleansException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } - } -} diff --git a/src/Squidex/Config/Orleans/ClientServices.cs b/src/Squidex/Config/Orleans/ClientServices.cs index 00742a9d8..1a7c58287 100644 --- a/src/Squidex/Config/Orleans/ClientServices.cs +++ b/src/Squidex/Config/Orleans/ClientServices.cs @@ -35,7 +35,7 @@ namespace Squidex.Config.Orleans .AddApplicationPartsFromReferences(typeof(XmlRepositoryGrain).Assembly) .UseStaticGatewayListProvider(options => { - options.Gateways.Add(new Uri("gwy.tcp://localhost:40000/0")); + options.Gateways.Add(new Uri("gwy.tcp://127.0.0.1:40000/0")); }) .Build(); diff --git a/src/Squidex/tslint.json b/src/Squidex/tslint.json index 6c694ec9f..2c629c93a 100644 --- a/src/Squidex/tslint.json +++ b/src/Squidex/tslint.json @@ -31,7 +31,6 @@ true, "spaces" ], - "invoke-injectable": true, "label-position": true, "max-line-length": [ true, @@ -99,11 +98,10 @@ ], "radix": true, "semicolon": [ + true, "always" ], "templates-no-negated-async": true, - "templates-use-public": true, - "template-to-ng-template": true, "trailing-comma": [ true, {