mirror of https://github.com/Squidex/squidex.git
24 changed files with 383 additions and 445 deletions
@ -1,79 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Squidex.Areas.Api.Config.Swagger; |
|
||||
using Squidex.Areas.Api.Controllers.Contents; |
|
||||
using Squidex.Areas.IdentityServer.Config; |
|
||||
using Squidex.Config; |
|
||||
using Squidex.Config.Authentication; |
|
||||
using Squidex.Config.Domain; |
|
||||
using Squidex.Config.Web; |
|
||||
using Squidex.Domain.Apps.Entities.Assets; |
|
||||
using Squidex.Domain.Apps.Entities.Contents; |
|
||||
using Squidex.Extensions.Actions.Twitter; |
|
||||
using Squidex.Infrastructure.Commands; |
|
||||
using Squidex.Infrastructure.Diagnostics; |
|
||||
using Squidex.Pipeline; |
|
||||
using Squidex.Pipeline.Robots; |
|
||||
|
|
||||
namespace Squidex |
|
||||
{ |
|
||||
public static class AppServices |
|
||||
{ |
|
||||
public static void AddAppServices(this IServiceCollection services, IConfiguration config) |
|
||||
{ |
|
||||
services.AddHttpClient(); |
|
||||
services.AddLogging(); |
|
||||
services.AddMemoryCache(); |
|
||||
services.AddOptions(); |
|
||||
|
|
||||
services.AddMyAssetServices(config); |
|
||||
services.AddMyAuthentication(config); |
|
||||
services.AddMyEntitiesServices(config); |
|
||||
services.AddMyEventPublishersServices(config); |
|
||||
services.AddMyEventStoreServices(config); |
|
||||
services.AddMyIdentityServer(); |
|
||||
services.AddMyInfrastructureServices(); |
|
||||
services.AddMyLoggingServices(config); |
|
||||
services.AddMyMigrationServices(); |
|
||||
services.AddMyMvc(); |
|
||||
services.AddMyRuleServices(); |
|
||||
services.AddMySerializers(); |
|
||||
services.AddMyStoreServices(config); |
|
||||
services.AddMySwaggerSettings(); |
|
||||
services.AddMySubscriptionServices(config); |
|
||||
|
|
||||
services.Configure<ContentOptions>( |
|
||||
config.GetSection("contents")); |
|
||||
services.Configure<AssetOptions>( |
|
||||
config.GetSection("assets")); |
|
||||
services.Configure<ReadonlyOptions>( |
|
||||
config.GetSection("mode")); |
|
||||
services.Configure<TwitterOptions>( |
|
||||
config.GetSection("twitter")); |
|
||||
services.Configure<RobotsTxtOptions>( |
|
||||
config.GetSection("robots")); |
|
||||
services.Configure<GCHealthCheckOptions>( |
|
||||
config.GetSection("healthz:gc")); |
|
||||
services.Configure<ETagOptions>( |
|
||||
config.GetSection("etags")); |
|
||||
|
|
||||
services.Configure<MyContentsControllerOptions>( |
|
||||
config.GetSection("contentsController")); |
|
||||
services.Configure<MyUrlsOptions>( |
|
||||
config.GetSection("urls")); |
|
||||
services.Configure<MyIdentityOptions>( |
|
||||
config.GetSection("identity")); |
|
||||
services.Configure<MyUIOptions>( |
|
||||
config.GetSection("ui")); |
|
||||
services.Configure<MyUsageOptions>( |
|
||||
config.GetSection("usage")); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,87 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Extensions.Hosting; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.Log; |
|
||||
using Squidex.Infrastructure.Migrations; |
|
||||
|
|
||||
namespace Squidex.Config.Domain |
|
||||
{ |
|
||||
public static class SystemExtensions |
|
||||
{ |
|
||||
public sealed class InitializeHostedService : IHostedService |
|
||||
{ |
|
||||
private readonly IEnumerable<IInitializable> targets; |
|
||||
private readonly IApplicationLifetime lifetime; |
|
||||
private readonly ISemanticLog log; |
|
||||
|
|
||||
public InitializeHostedService(IEnumerable<IInitializable> targets, IApplicationLifetime lifetime, ISemanticLog log) |
|
||||
{ |
|
||||
this.targets = targets; |
|
||||
this.lifetime = lifetime; |
|
||||
this.log = log; |
|
||||
} |
|
||||
|
|
||||
public async Task StartAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
foreach (var target in targets) |
|
||||
{ |
|
||||
await target.InitializeAsync(cancellationToken); |
|
||||
|
|
||||
log.LogInformation(w => w.WriteProperty("initializedSystem", target.GetType().Name)); |
|
||||
} |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
lifetime.StopApplication(); |
|
||||
throw; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public Task StopAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public sealed class MigratorHostedService : IHostedService |
|
||||
{ |
|
||||
private readonly IApplicationLifetime lifetime; |
|
||||
private readonly Migrator migrator; |
|
||||
|
|
||||
public MigratorHostedService(IApplicationLifetime lifetime, Migrator migrator) |
|
||||
{ |
|
||||
this.lifetime = lifetime; |
|
||||
this.migrator = migrator; |
|
||||
} |
|
||||
|
|
||||
public async Task StartAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
await migrator.MigrateAsync(); |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
lifetime.StopApplication(); |
|
||||
throw; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public Task StopAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,34 +1,113 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Net; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Hosting; |
|
||||
using Orleans; |
using Orleans; |
||||
|
using Orleans.Configuration; |
||||
|
using Orleans.Hosting; |
||||
|
using Squidex.Domain.Apps.Entities.Contents; |
||||
|
using Squidex.Domain.Apps.Entities.Rules; |
||||
|
using Squidex.Domain.Apps.Entities.Rules.UsageTracking; |
||||
|
using Squidex.Infrastructure.EventSourcing.Grains; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
namespace Squidex.Config.Orleans |
namespace Squidex.Config.Orleans |
||||
{ |
{ |
||||
public static class OrleansServices |
public static class OrleansServices |
||||
{ |
{ |
||||
public static void AddOrleansSilo(this IServiceCollection services) |
public static IServiceProvider AddAndBuildOrleans(this IServiceCollection services, IConfiguration config) |
||||
{ |
{ |
||||
services.AddSingletonAs<SiloWrapper>() |
services.Configure<ClusterOptions>(options => |
||||
.As<IHostedService>() |
{ |
||||
.AsSelf(); |
options.Configure(); |
||||
|
}); |
||||
|
|
||||
|
services.Configure<ProcessExitHandlingOptions>(options => |
||||
|
{ |
||||
|
options.FastKillOnProcessExit = false; |
||||
|
}); |
||||
|
|
||||
services.AddServicesForSelfHostedDashboard(null, options => |
services.AddServicesForSelfHostedDashboard(null, options => |
||||
{ |
{ |
||||
options.HideTrace = true; |
options.HideTrace = true; |
||||
}); |
}); |
||||
|
|
||||
services.AddSingletonAs(c => c.GetRequiredService<IClusterClient>()) |
services.AddHostedService<SiloHost>(); |
||||
.As<IClusterClient>(); |
|
||||
|
var hostBuilder = new SiloHostBuilder() |
||||
|
.UseDashboardEx() |
||||
|
.EnableDirectClient() |
||||
|
.AddIncomingGrainCallFilter<LocalCacheFilter>() |
||||
|
.AddStartupTask<Bootstrap<IContentSchedulerGrain>>() |
||||
|
.AddStartupTask<Bootstrap<IEventConsumerManagerGrain>>() |
||||
|
.AddStartupTask<Bootstrap<IRuleDequeuerGrain>>() |
||||
|
.AddStartupTask<Bootstrap<IUsageTrackerGrain>>() |
||||
|
.ConfigureApplicationParts(builder => |
||||
|
{ |
||||
|
builder.AddMyParts(); |
||||
|
}); |
||||
|
|
||||
|
config.ConfigureByOption("orleans:clustering", new Options |
||||
|
{ |
||||
|
["MongoDB"] = () => |
||||
|
{ |
||||
|
hostBuilder.ConfigureEndpoints(Dns.GetHostName(), 11111, 40000, listenOnAnyHostAddress: true); |
||||
|
|
||||
|
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration"); |
||||
|
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database"); |
||||
|
|
||||
|
hostBuilder.UseMongoDBClustering(options => |
||||
|
{ |
||||
|
options.ConnectionString = mongoConfiguration; |
||||
|
options.CollectionPrefix = "Orleans_"; |
||||
|
options.DatabaseName = mongoDatabaseName; |
||||
|
}); |
||||
|
}, |
||||
|
["Development"] = () => |
||||
|
{ |
||||
|
hostBuilder.UseLocalhostClustering(gatewayPort: 40000, serviceId: Constants.OrleansClusterId, clusterId: Constants.OrleansClusterId); |
||||
|
hostBuilder.Configure<ClusterMembershipOptions>(options => options.ExpectedClusterSize = 1); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
config.ConfigureByOption("store:type", new Options |
||||
|
{ |
||||
|
["MongoDB"] = () => |
||||
|
{ |
||||
|
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration"); |
||||
|
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database"); |
||||
|
|
||||
|
hostBuilder.UseMongoDBReminders(options => |
||||
|
{ |
||||
|
options.ConnectionString = mongoConfiguration; |
||||
|
options.CollectionPrefix = "Orleans_"; |
||||
|
options.DatabaseName = mongoDatabaseName; |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
IServiceProvider provider = null; |
||||
|
|
||||
|
hostBuilder.UseServiceProviderFactory((siloServices) => |
||||
|
{ |
||||
|
foreach (var descriptor in services) |
||||
|
{ |
||||
|
siloServices.Add(descriptor); |
||||
|
} |
||||
|
|
||||
|
provider = siloServices.BuildServiceProvider(); |
||||
|
|
||||
|
return provider; |
||||
|
}).Build(); |
||||
|
|
||||
services.AddSingletonAs(c => c.GetRequiredService<SiloWrapper>().Client) |
return provider; |
||||
.As<IGrainFactory>(); |
|
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,51 @@ |
|||||
|
// ==========================================================================
|
||||
|
// 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 Microsoft.Extensions.Logging; |
||||
|
using Orleans.Hosting; |
||||
|
using Squidex.Config.Startup; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Log; |
||||
|
|
||||
|
namespace Squidex.Config.Orleans |
||||
|
{ |
||||
|
public sealed class SiloHost : SafeHostedService |
||||
|
{ |
||||
|
private readonly ISiloHost silo; |
||||
|
|
||||
|
public SiloHost(ISiloHost silo, ISemanticLog log, IApplicationLifetime lifetime) |
||||
|
: base(lifetime, log) |
||||
|
{ |
||||
|
this.silo = silo; |
||||
|
} |
||||
|
|
||||
|
protected override async Task StartAsync(ISemanticLog log, CancellationToken ct) |
||||
|
{ |
||||
|
var watch = ValueStopwatch.StartNew(); |
||||
|
try |
||||
|
{ |
||||
|
await silo.StartAsync(ct); |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
var elapsedMs = watch.Stop(); |
||||
|
|
||||
|
log.LogInformation(w => w |
||||
|
.WriteProperty("message", "Silo started") |
||||
|
.WriteProperty("elapsedMs", elapsedMs)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override async Task StopAsync(ISemanticLog log, CancellationToken ct) |
||||
|
{ |
||||
|
await silo.StopAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,42 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Orleans.Hosting; |
|
||||
|
|
||||
namespace Squidex.Config.Orleans |
|
||||
{ |
|
||||
public static class SiloServices |
|
||||
{ |
|
||||
public static void AddAppSiloServices(this IServiceCollection services, IConfiguration config) |
|
||||
{ |
|
||||
config.ConfigureByOption("store:type", new Options |
|
||||
{ |
|
||||
["MongoDB"] = () => |
|
||||
{ |
|
||||
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration"); |
|
||||
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database"); |
|
||||
|
|
||||
services.AddMongoDBMembershipTable(options => |
|
||||
{ |
|
||||
options.ConnectionString = mongoConfiguration; |
|
||||
options.CollectionPrefix = "Orleans_"; |
|
||||
options.DatabaseName = mongoDatabaseName; |
|
||||
}); |
|
||||
|
|
||||
services.AddMongoDBReminders(options => |
|
||||
{ |
|
||||
options.ConnectionString = mongoConfiguration; |
|
||||
options.CollectionPrefix = "Orleans_"; |
|
||||
options.DatabaseName = mongoDatabaseName; |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,190 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Net; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Hosting; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using Orleans; |
|
||||
using Orleans.Configuration; |
|
||||
using Orleans.Hosting; |
|
||||
using Squidex.Domain.Apps.Entities.Contents; |
|
||||
using Squidex.Domain.Apps.Entities.Rules; |
|
||||
using Squidex.Domain.Apps.Entities.Rules.UsageTracking; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.EventSourcing.Grains; |
|
||||
using Squidex.Infrastructure.Log; |
|
||||
using Squidex.Infrastructure.Log.Adapter; |
|
||||
using Squidex.Infrastructure.Orleans; |
|
||||
|
|
||||
namespace Squidex.Config.Orleans |
|
||||
{ |
|
||||
public sealed class SiloWrapper : IHostedService |
|
||||
{ |
|
||||
private readonly Lazy<ISiloHost> lazySilo; |
|
||||
private readonly ISemanticLog log; |
|
||||
private readonly IApplicationLifetime lifetime; |
|
||||
private bool isStopping; |
|
||||
|
|
||||
internal sealed class Source : IConfigurationSource |
|
||||
{ |
|
||||
private readonly IConfigurationProvider configurationProvider; |
|
||||
|
|
||||
public Source(IConfigurationProvider configurationProvider) |
|
||||
{ |
|
||||
this.configurationProvider = configurationProvider; |
|
||||
} |
|
||||
|
|
||||
public IConfigurationProvider Build(IConfigurationBuilder builder) |
|
||||
{ |
|
||||
return configurationProvider; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public IClusterClient Client |
|
||||
{ |
|
||||
get { return lazySilo.Value.Services.GetRequiredService<IClusterClient>(); } |
|
||||
} |
|
||||
|
|
||||
public SiloWrapper(IConfiguration config, ISemanticLog log, IApplicationLifetime lifetime) |
|
||||
{ |
|
||||
this.lifetime = lifetime; |
|
||||
this.log = log; |
|
||||
|
|
||||
lazySilo = new Lazy<ISiloHost>(() => |
|
||||
{ |
|
||||
var hostBuilder = new SiloHostBuilder() |
|
||||
.UseDashboard(options => options.HostSelf = false) |
|
||||
.EnableDirectClient() |
|
||||
.AddIncomingGrainCallFilter<LocalCacheFilter>() |
|
||||
.AddStartupTask<InitializerStartup>() |
|
||||
.AddStartupTask<Bootstrap<IContentSchedulerGrain>>() |
|
||||
.AddStartupTask<Bootstrap<IEventConsumerManagerGrain>>() |
|
||||
.AddStartupTask<Bootstrap<IRuleDequeuerGrain>>() |
|
||||
.AddStartupTask<Bootstrap<IUsageTrackerGrain>>() |
|
||||
.Configure<ClusterOptions>(options => |
|
||||
{ |
|
||||
options.Configure(); |
|
||||
}) |
|
||||
.ConfigureApplicationParts(builder => |
|
||||
{ |
|
||||
builder.AddMyParts(); |
|
||||
}) |
|
||||
.ConfigureLogging((hostingContext, builder) => |
|
||||
{ |
|
||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("logging")); |
|
||||
builder.AddSemanticLog(); |
|
||||
builder.AddFilter(); |
|
||||
}) |
|
||||
.ConfigureServices((context, services) => |
|
||||
{ |
|
||||
services.AddAppSiloServices(context.Configuration); |
|
||||
services.AddAppServices(context.Configuration); |
|
||||
|
|
||||
services.Configure<ProcessExitHandlingOptions>(options => options.FastKillOnProcessExit = false); |
|
||||
}) |
|
||||
.ConfigureAppConfiguration((hostContext, builder) => |
|
||||
{ |
|
||||
if (config is IConfigurationRoot root) |
|
||||
{ |
|
||||
foreach (var provider in root.Providers) |
|
||||
{ |
|
||||
builder.Add(new Source(provider)); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
config.ConfigureByOption("orleans:clustering", new Options |
|
||||
{ |
|
||||
["MongoDB"] = () => |
|
||||
{ |
|
||||
hostBuilder.ConfigureEndpoints(Dns.GetHostName(), 11111, 40000, listenOnAnyHostAddress: true); |
|
||||
|
|
||||
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration"); |
|
||||
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database"); |
|
||||
|
|
||||
hostBuilder.UseMongoDBClustering(options => |
|
||||
{ |
|
||||
options.ConnectionString = mongoConfiguration; |
|
||||
options.CollectionPrefix = "Orleans_"; |
|
||||
options.DatabaseName = mongoDatabaseName; |
|
||||
}); |
|
||||
}, |
|
||||
["Development"] = () => |
|
||||
{ |
|
||||
hostBuilder.UseLocalhostClustering(gatewayPort: 40000, serviceId: Constants.OrleansClusterId, clusterId: Constants.OrleansClusterId); |
|
||||
hostBuilder.Configure<ClusterMembershipOptions>(options => options.ExpectedClusterSize = 1); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
config.ConfigureByOption("store:type", new Options |
|
||||
{ |
|
||||
["MongoDB"] = () => |
|
||||
{ |
|
||||
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration"); |
|
||||
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database"); |
|
||||
|
|
||||
hostBuilder.UseMongoDBReminders(options => |
|
||||
{ |
|
||||
options.ConnectionString = mongoConfiguration; |
|
||||
options.CollectionPrefix = "Orleans_"; |
|
||||
options.DatabaseName = mongoDatabaseName; |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
var silo = hostBuilder.Build(); |
|
||||
|
|
||||
silo.Stopped.ContinueWith(x => |
|
||||
{ |
|
||||
if (!isStopping) |
|
||||
{ |
|
||||
lifetime.StopApplication(); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
return silo; |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
public async Task StartAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var watch = ValueStopwatch.StartNew(); |
|
||||
try |
|
||||
{ |
|
||||
await lazySilo.Value.StartAsync(cancellationToken); |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
lifetime.StopApplication(); |
|
||||
throw; |
|
||||
} |
|
||||
finally |
|
||||
{ |
|
||||
var elapsedMs = watch.Stop(); |
|
||||
|
|
||||
log.LogInformation(w => w |
|
||||
.WriteProperty("message", "Silo started") |
|
||||
.WriteProperty("elapsedMs", elapsedMs)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public async Task StopAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (lazySilo.IsValueCreated) |
|
||||
{ |
|
||||
isStopping = true; |
|
||||
|
|
||||
await lazySilo.Value.StopAsync(cancellationToken); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,38 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Log; |
||||
|
|
||||
|
namespace Squidex.Config.Startup |
||||
|
{ |
||||
|
public sealed class InitializerHost : SafeHostedService |
||||
|
{ |
||||
|
private readonly IEnumerable<IInitializable> targets; |
||||
|
|
||||
|
public InitializerHost(IEnumerable<IInitializable> targets, IApplicationLifetime lifetime, ISemanticLog log) |
||||
|
: base(lifetime, log) |
||||
|
{ |
||||
|
this.targets = targets; |
||||
|
} |
||||
|
|
||||
|
protected override async Task StartAsync(ISemanticLog log, CancellationToken ct) |
||||
|
{ |
||||
|
foreach (var target in targets.Distinct()) |
||||
|
{ |
||||
|
await target.InitializeAsync(ct); |
||||
|
|
||||
|
log.LogInformation(w => w.WriteProperty("initializedSystem", target.GetType().Name)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 Squidex.Infrastructure.Log; |
||||
|
using Squidex.Infrastructure.Migrations; |
||||
|
|
||||
|
namespace Squidex.Config.Startup |
||||
|
{ |
||||
|
public sealed class MigratorHost : SafeHostedService |
||||
|
{ |
||||
|
private readonly Migrator migrator; |
||||
|
|
||||
|
public MigratorHost(Migrator migrator, IApplicationLifetime lifetime, ISemanticLog log) |
||||
|
: base(lifetime, log) |
||||
|
{ |
||||
|
this.migrator = migrator; |
||||
|
} |
||||
|
|
||||
|
protected override Task StartAsync(ISemanticLog log, CancellationToken ct) |
||||
|
{ |
||||
|
return migrator.MigrateAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
// ==========================================================================
|
||||
|
// 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 Squidex.Infrastructure.Log; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
|
||||
|
namespace Squidex.Config.Startup |
||||
|
{ |
||||
|
public abstract class SafeHostedService : IHostedService |
||||
|
{ |
||||
|
private readonly IApplicationLifetime lifetime; |
||||
|
private readonly ISemanticLog log; |
||||
|
private bool isStarted; |
||||
|
|
||||
|
protected SafeHostedService(IApplicationLifetime lifetime, ISemanticLog log) |
||||
|
{ |
||||
|
this.lifetime = lifetime; |
||||
|
|
||||
|
this.log = log; |
||||
|
} |
||||
|
|
||||
|
public async Task StartAsync(CancellationToken cancellationToken) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
await StartAsync(log, cancellationToken); |
||||
|
|
||||
|
isStarted = true; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
lifetime.StopApplication(); |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task StopAsync(CancellationToken cancellationToken) |
||||
|
{ |
||||
|
if (isStarted) |
||||
|
{ |
||||
|
await StopAsync(log, cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected abstract Task StartAsync(ISemanticLog log, CancellationToken ct); |
||||
|
|
||||
|
protected virtual Task StopAsync(ISemanticLog log, CancellationToken ct) |
||||
|
{ |
||||
|
return TaskHelper.Done; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue