Browse Source

Added rebuilder.

pull/351/head
Sebastian Stehle 7 years ago
parent
commit
92780b99af
  1. 3
      src/Squidex/Config/Domain/EntitiesServices.cs
  2. 31
      src/Squidex/Config/Startup/RebuilderHost.cs
  3. 4
      src/Squidex/WebStartup.cs
  4. 23
      src/Squidex/appsettings.json
  5. 3
      tools/Migrate_01/MigrationPath.cs
  6. 22
      tools/Migrate_01/RebuildOptions.cs
  7. 57
      tools/Migrate_01/RebuildRunner.cs
  8. 78
      tools/Migrate_01/Rebuilder.cs

3
src/Squidex/Config/Domain/EntitiesServices.cs

@ -239,6 +239,9 @@ namespace Squidex.Config.Domain
services.AddTransientAs<Rebuilder>()
.AsSelf();
services.AddTransientAs<RebuildRunner>()
.AsSelf();
services.AddTransientAs<MigrationPath>()
.As<IMigrationPath>();

31
src/Squidex/Config/Startup/RebuilderHost.cs

@ -0,0 +1,31 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Migrate_01;
using Squidex.Infrastructure.Log;
namespace Squidex.Config.Startup
{
public sealed class RebuilderHost : SafeHostedService
{
private readonly RebuildRunner rebuildRunner;
public RebuilderHost(IApplicationLifetime lifetime, ISemanticLog log, RebuildRunner rebuildRunner)
: base(lifetime, log)
{
this.rebuildRunner = rebuildRunner;
}
protected override Task StartAsync(ISemanticLog log, CancellationToken ct)
{
return rebuildRunner.RunAsync(ct);
}
}
}

4
src/Squidex/WebStartup.cs

@ -9,6 +9,7 @@ using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Migrate_01;
using Squidex.Areas.Api;
using Squidex.Areas.Api.Config.Swagger;
using Squidex.Areas.Api.Controllers.Contents;
@ -82,6 +83,8 @@ namespace Squidex
config.GetSection("healthz:gc"));
services.Configure<ETagOptions>(
config.GetSection("etags"));
services.Configure<RebuildOptions>(
config.GetSection("rebuild"));
services.Configure<MyContentsControllerOptions>(
config.GetSection("contentsController"));
@ -100,6 +103,7 @@ namespace Squidex
{
afterServices.AddHostedService<InitializerHost>();
afterServices.AddHostedService<MigratorHost>();
afterServices.AddHostedService<RebuilderHost>();
});
return provider;

23
src/Squidex/appsettings.json

@ -341,5 +341,28 @@
* The deepl api key if you want to support automated translations.
*/
"deeplAuthKey": ""
},
"rebuild": {
/*
* Set to true to rebuild apps.
*/
"apps": false,
/*
* Set to true to rebuild assets.
*/
"assets": false,
/*
* Set to true to rebuild contents.
*/
"contents": false,
/*
* Set to true to rebuild rules.
*/
"rules": false,
/*
* Set to true to rebuild schemas.
*/
"schemas": false
}
}

3
tools/Migrate_01/MigrationPath.cs

@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Migrate_01.Migrations;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Migrations;
namespace Migrate_01
@ -21,6 +22,8 @@ namespace Migrate_01
public MigrationPath(IServiceProvider serviceProvider)
{
Guard.NotNull(serviceProvider, nameof(serviceProvider));
this.serviceProvider = serviceProvider;
}

22
tools/Migrate_01/RebuildOptions.cs

@ -0,0 +1,22 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Migrate_01
{
public sealed class RebuildOptions
{
public bool Apps { get; set; }
public bool Assets { get; set; }
public bool Contents { get; set; }
public bool Rules { get; set; }
public bool Schemas { get; set; }
}
}

57
tools/Migrate_01/RebuildRunner.cs

@ -0,0 +1,57 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Squidex.Infrastructure;
namespace Migrate_01
{
public sealed class RebuildRunner
{
private readonly Rebuilder rebuilder;
private readonly RebuildOptions rebuildOptions;
public RebuildRunner(Rebuilder rebuilder, IOptions<RebuildOptions> rebuildOptions)
{
Guard.NotNull(rebuilder, nameof(rebuilder));
Guard.NotNull(rebuildOptions, nameof(rebuildOptions));
this.rebuilder = rebuilder;
this.rebuildOptions = rebuildOptions.Value;
}
public async Task RunAsync(CancellationToken ct)
{
if (rebuildOptions.Apps)
{
await rebuilder.RebuildAppsAsync(ct);
}
if (rebuildOptions.Schemas)
{
await rebuilder.RebuildSchemasAsync(ct);
}
if (rebuildOptions.Rules)
{
await rebuilder.RebuildRulesAsync(ct);
}
if (rebuildOptions.Assets)
{
await rebuilder.RebuildAssetsAsync(ct);
}
if (rebuildOptions.Contents)
{
await rebuilder.RebuildContentAsync(ct);
}
}
}
}

78
tools/Migrate_01/Rebuilder.cs

@ -39,80 +39,84 @@ namespace Migrate_01
IStore<Guid> store,
IEventStore eventStore)
{
Guard.NotNull(eventStore, nameof(eventStore));
Guard.NotNull(localCache, nameof(localCache));
Guard.NotNull(store, nameof(store));
this.eventStore = eventStore;
this.localCache = localCache;
this.store = store;
}
public async Task RebuildAppsAsync()
public async Task RebuildAppsAsync(CancellationToken ct = default)
{
await store.GetSnapshotStore<AppState>().ClearAsync();
await RebuildManyAsync("^app\\-", id => RebuildAsync<AppState, AppGrain>(id, (e, s) => s.Apply(e)));
await RebuildManyAsync("^app\\-", id => RebuildAsync<AppState, AppGrain>(id, (e, s) => s.Apply(e)), ct);
}
public async Task RebuildSchemasAsync()
public async Task RebuildSchemasAsync(CancellationToken ct = default)
{
await store.GetSnapshotStore<SchemaState>().ClearAsync();
await RebuildManyAsync("^schema\\-", id => RebuildAsync<SchemaState, SchemaGrain>(id, (e, s) => s.Apply(e)));
await RebuildManyAsync("^schema\\-", id => RebuildAsync<SchemaState, SchemaGrain>(id, (e, s) => s.Apply(e)), ct);
}
public async Task RebuildRulesAsync()
public async Task RebuildRulesAsync(CancellationToken ct = default)
{
await store.GetSnapshotStore<RuleState>().ClearAsync();
await RebuildManyAsync("^rule\\-", id => RebuildAsync<RuleState, RuleGrain>(id, (e, s) => s.Apply(e)));
await RebuildManyAsync("^rule\\-", id => RebuildAsync<RuleState, RuleGrain>(id, (e, s) => s.Apply(e)), ct);
}
public async Task RebuildAssetsAsync()
public async Task RebuildAssetsAsync(CancellationToken ct = default)
{
await store.GetSnapshotStore<AssetState>().ClearAsync();
await RebuildManyAsync("^asset\\-", id => RebuildAsync<AssetState, AssetGrain>(id, (e, s) => s.Apply(e)));
await RebuildManyAsync("^asset\\-", id => RebuildAsync<AssetState, AssetGrain>(id, (e, s) => s.Apply(e)), ct);
}
public async Task RebuildContentAsync()
public async Task RebuildContentAsync(CancellationToken ct = default)
{
using (localCache.StartContext())
{
await store.GetSnapshotStore<ContentState>().ClearAsync();
await store.GetSnapshotStore<ContentState>().ClearAsync();
await RebuildManyAsync("^content\\-", async id =>
await RebuildManyAsync("^content\\-", async id =>
{
try
{
try
{
await RebuildAsync<ContentState, ContentGrain>(id, (e, s) => s.Apply(e));
}
catch (DomainObjectNotFoundException)
{
return;
}
});
}
await RebuildAsync<ContentState, ContentGrain>(id, (e, s) => s.Apply(e));
}
catch (DomainObjectNotFoundException)
{
return;
}
}, ct);
}
private async Task RebuildManyAsync(string filter, Func<Guid, Task> action)
private async Task RebuildManyAsync(string filter, Func<Guid, Task> action, CancellationToken ct)
{
var handledIds = new HashSet<Guid>();
var worker = new ActionBlock<Guid>(action, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 32 });
await eventStore.QueryAsync(async storedEvent =>
using (localCache.StartContext())
{
var headers = storedEvent.Data.Headers;
var handledIds = new HashSet<Guid>();
var id = headers.AggregateId();
var worker = new ActionBlock<Guid>(action, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 32 });
if (handledIds.Add(id))
await eventStore.QueryAsync(async storedEvent =>
{
await worker.SendAsync(id);
}
}, filter, ct: CancellationToken.None);
var headers = storedEvent.Data.Headers;
worker.Complete();
var id = headers.AggregateId();
await worker.Completion;
if (handledIds.Add(id))
{
await worker.SendAsync(id);
}
}, filter, ct);
worker.Complete();
await worker.Completion;
}
}
private async Task RebuildAsync<TState, TGrain>(Guid key, Func<Envelope<IEvent>, TState, TState> func) where TState : IDomainState, new()

Loading…
Cancel
Save