private static async Task <ISiloHost> StartSilo() { var invariant = "System.Data.SqlClient"; // for Microsoft SQL Server var connectionString = @"Data Source=.;Initial Catalog=Orleans;User Id=sa;Password=8E62-E21CBE62311F;Integrated Security=True;Pooling=False;Max Pool Size=200;MultipleActiveResultSets=True"; //var connectionString = @"Data Source=.;Initial Catalog=Orleans;User Id=sa;Password=123456;Integrated Security=True;Pooling=False;Max Pool Size=200;MultipleActiveResultSets=True"; var siloPort = GetAvailablePort(11111, 11119); var gatewayPort = GetAvailablePort(30000, 30009); var healthCheckPort = GetAvailablePort(8880, 8889); // define the cluster configuration var builder = new SiloHostBuilder() //监听的主silo 远程连接点 为空则创建一个主silo连接点 //.UseDevelopmentClustering(new IPEndPoint(IPAddress.Parse("192.168.3.17"), 11111)) .Configure <ClusterOptions>(options => { options.ClusterId = "dev"; options.ServiceId = "BaseService"; }) .UseAdoNetClustering(options => { options.ConnectionString = connectionString; options.Invariant = invariant; }) .UseAdoNetReminderService(options => { options.Invariant = invariant; options.ConnectionString = connectionString; }) .AddAdoNetGrainStorage("GrainStorageForBaseService", options => { options.Invariant = invariant; options.ConnectionString = connectionString; }) //.ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000) .ConfigureLogging(logger => logger.AddConsole()) .Configure <EndpointOptions>(options => { // Port to use for Silo-to-Silo options.SiloPort = 11111; // Port to use for the gateway options.GatewayPort = 30000; // IP Address to advertise in the cluster options.AdvertisedIPAddress = IPAddress.Parse(GetExternalIpAddress());// 映射外网IP // The socket used for silo-to-silo will bind to this endpoint options.GatewayPort = 30000; options.GatewayListeningEndpoint = new IPEndPoint(IPAddress.Any, options.GatewayPort); // The socket used by the gateway will bind to this endpoint options.SiloListeningEndpoint = new IPEndPoint(IPAddress.Any, options.SiloPort); }) .ConfigureServices(service => { service.AddHealthChecks() .AddCheck <GrainHealthCheck>("GrainHealth") .AddCheck <SiloHealthCheck>("SiloHealth") .AddCheck <StorageHealthCheck>("StorageHealth") .AddCheck <ClusterHealthCheck>("ClusterHealth"); service.AddSingleton <IHealthCheckPublisher, LoggingHealthCheckPublisher>() .Configure <HealthCheckPublisherOptions>(options => { options.Period = TimeSpan.FromSeconds(1); }); service.Configure <ConsoleLifetimeOptions>(options => { options.SuppressStatusMessages = true; }); service.Configure <HealthCheckHostedServiceOptions>(options => { options.Port = healthCheckPort; options.PathString = "/health"; }); service.AddLogging(logger => logger.AddConsole()); }); var host = builder.Build(); await host.StartAsync(); return(host); }
public static void Main(string[] args) { var externalAssemblies = LoadExternalAssemblies().ToArray(); var env = Environment.GetEnvironmentVariable("ORLEANS_CONFIG"); var builder = new SiloHostBuilder(); builder .ConfigureLogging((context, loggingBuilder) => loggingBuilder.AddConsole()) .Configure <ProcessExitHandlingOptions>(options => { options.FastKillOnProcessExit = false; }) .Configure <ClusterOptions>(options => { options.ClusterId = "serverlessorleans"; options.ServiceId = "serverlessorleans"; }) .ConfigureApplicationParts(parts => { foreach (var assembly in externalAssemblies) { System.Console.WriteLine("Loading orleans app parts: " + assembly.FullName); parts.AddApplicationPart(assembly); } }) .UseDashboard(options => { options.CounterUpdateIntervalMs = 5000; options.HostSelf = false; }); if (env == "STORAGE") { builder .AddAzureBlobGrainStorageAsDefault(options => { options.ConnectionString = Environment.GetEnvironmentVariable("StorageConnectionString"); options.UseJson = true; options.IndentJson = true; options.ContainerName = "actorstate"; }) .UseAzureStorageClustering(options => { options.ConnectionString = Environment.GetEnvironmentVariable("StorageConnectionString"); options.TableName = "clusterstate"; }) .ConfigureEndpoints(11111, 30000); } else if (env == "SQL") { builder .AddAdoNetGrainStorageAsDefault(options => { options.Invariant = "System.Data.SqlClient"; options.UseJsonFormat = true; options.IndentJson = true; options.ConnectionString = Environment.GetEnvironmentVariable("SqlConnectionString"); }) .UseAdoNetClustering(options => { options.Invariant = "System.Data.SqlClient"; options.ConnectionString = Environment.GetEnvironmentVariable("SqlConnectionString"); }) .ConfigureEndpoints(11111, 30000); } else { throw new Exception("ORLEANS_CONFIG envvar not defined."); } _silo = builder.Build(); Task.Run(StartSilo); AssemblyLoadContext.Default.Unloading += context => { Task.Run(StopSilo); _siloStopped.WaitOne(); }; _siloStopped.WaitOne(); }
public SiloWrapper(IConfiguration config, ISemanticLog log) { this.log = log; silo = new Lazy <ISiloHost>(() => { var hostBuilder = new SiloHostBuilder() .UseDashboard(options => options.HostSelf = false) .AddIncomingGrainCallFilter <LocalCacheFilter>() .AddStartupTask <Bootstrap <IContentSchedulerGrain> >() .AddStartupTask <Bootstrap <IEventConsumerManagerGrain> >() .AddStartupTask <Bootstrap <IRuleDequeuerGrain> >() .AddStartupTask((services, ct) => { services.RunInitialization(); return(TaskHelper.Done); }) .Configure <ClusterOptions>(options => { options.ClusterId = "squidex"; }) .ConfigureLogging((hostingContext, builder) => { builder.AddConfiguration(hostingContext.Configuration.GetSection("logging")); builder.AddSemanticLog(); builder.AddFilter(); }) .ConfigureApplicationParts(builder => { builder.AddApplicationPart(SquidexEntities.Assembly); builder.AddApplicationPart(SquidexInfrastructure.Assembly); }) .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(ConfigUtilities.SiloAddress, 11111, 40000, 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, clusterId: "squidex"); 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; }); } }); return(hostBuilder.Build()); }); }
private static ISiloHost ConfigureSilo() { var builder = new ConfigurationBuilder() .AddJsonFile($"appsettings.json", true, true) .AddJsonFile($"appsettings.{EnvironmentName}.json", true, true) .AddEnvironmentVariables(); Configuration = builder.Build(); var siloHostBuilder = new SiloHostBuilder(); BsonClassMap.RegisterClassMap <AccountEvent>(cm => { cm.AutoMap(); cm.SetIsRootClass(true); }); BsonClassMap.RegisterClassMap <AccountNameEvent>(); BsonClassMap.RegisterClassMap <DepositEvent>(); BsonClassMap.RegisterClassMap <NewStakeholderEvent>(); BsonClassMap.RegisterClassMap <NewTransactionEvent>(); BsonClassMap.RegisterClassMap <WithdrawEvent>(); IMongoDatabase database; siloHostBuilder.Configure <ClusterOptions>(options => { options.ClusterId = "dev"; options.ServiceId = "bancor-silohost"; }); switch (EnvironmentName) { case "Integration": siloHostBuilder .UseConsulClustering(options => { options.Address = new Uri("http://consul:8500"); }) .ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000); database = new MongoDbFactory().Create(); break; case "Development": siloHostBuilder .UseLocalhostClustering() .Configure <EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback); database = new MongoDbFactory().Create("mongodb://localhost:27017"); break; default: throw new Exception($"Unknown environment '{EnvironmentName}'"); } siloHostBuilder.Configure <ClusterOptions>(options => { options.ClusterId = "dev"; options.ServiceId = "bancor"; }) .ConfigureServices(s => s.TryAddSingleton <IGrainStorage, MongoCustomerStorageProvider>()) .ConfigureServices(s => s.TryAddTransient <ICustomerRepository, CustomerRepository>()) .ConfigureServices(s => s.TryAddSingleton(database)) .ConfigureServices(s => s.TryAddTransient <IJournaldAccountRepository, JournalAccountRepository>()) .ConfigureServices(s => s.AddSingletonNamedService <IGrainStorage>("CustomerStorageProvider", (x, y) => new MongoCustomerStorageProvider(database, (IGrainFactory)x.GetService(typeof(IGrainFactory))))) .ConfigureLogging(logging => logging.AddConsole()) .AddMemoryGrainStorageAsDefault() .AddSimpleMessageStreamProvider("SMSProvider") .AddMemoryGrainStorage("PubSubStore") .AddCustomStorageBasedLogConsistencyProvider("CustomStorage") .UseTransactions(); var host = siloHostBuilder.Build(); return(host); }
private static async Task <ISiloHost> CreateSilo() { var conf = new RedisConfiguration() { AbortOnConnectFail = true, Hosts = new RedisHost[] { new RedisHost { Host = Configuration.GetSection("RedisCache")["Connection"], Port = int.Parse(Configuration.GetSection("RedisCache")["Port"]) } }, AllowAdmin = true, ConnectTimeout = 1000, ServerEnumerationStrategy = new ServerEnumerationStrategy() { Mode = ServerEnumerationStrategy.ModeOptions.All, TargetRole = ServerEnumerationStrategy.TargetRoleOptions.Any, UnreachableServerAction = ServerEnumerationStrategy.UnreachableServerActionOptions.Throw } }; var builder = new SiloHostBuilder() .Configure <ClusterOptions>(options => { options.ClusterId = Configuration.GetSection("Orleans")["ClusterId"]; options.ServiceId = Configuration.GetSection("Orleans")["ServiceId"]; }) .Configure <SchedulingOptions>(options => { options.AllowCallChainReentrancy = true; options.PerformDeadlockDetection = true; }) .Configure <SerializationProviderOptions>(options => { options.SerializationProviders.Add(typeof(ProtobufNetSerializer)); options.FallbackSerializationProvider = typeof(ProtobufNetSerializer); }) .Configure <EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback) .UseMongoDBClient(Configuration.GetSection("Orleans")["Connection"]) .UseMongoDBReminders(options => { options.DatabaseName = Configuration.GetSection("Orleans")["Database"]; options.CreateShardKeyForCosmos = false; }) .UseMongoDBClustering(c => { c.DatabaseName = Configuration.GetSection("Orleans")["Database"]; c.CreateShardKeyForCosmos = false; }) .AddMongoDBGrainStorageAsDefault(c => c.Configure(options => { options.DatabaseName = Configuration.GetSection("Orleans")["Database"]; options.CreateShardKeyForCosmos = false; })) .AddMongoDBGrainStorage("PubSubStore", options => { options.DatabaseName = Configuration.GetSection("Orleans")["Database"]; options.CreateShardKeyForCosmos = false; }) .ConfigureLogging(builder => { builder.AddSerilog(new LoggerConfiguration() .Enrich.WithMachineName() .ReadFrom.Configuration(Configuration) .CreateLogger()); }) .AddStartupTask <NStartupTask>() .ConfigureApplicationParts(parts => { parts.AddFromApplicationBaseDirectory().WithReferences(); }) //.AddApplicationPart(typeof(Node).Assembly).WithReferences()) .ConfigureServices(services => { services.AddIdGenerator(x => { string appIdStr = Configuration.GetSection("IdGen")["AppId"]; if (!ushort.TryParse(appIdStr, out ushort appid)) { throw new Exception("Please config appid in 'config.json'"); } x.AppId = appid; x.GeneratorOptions = new IdGeneratorOptions(); // Let's say we take april 1st 2020 as our epoch var epoch = DateTime.Parse(Configuration.GetSection("IdGen")["Epoch"]); byte timestampBits = byte.Parse(Configuration.GetSection("IdGen")["TimestampBits"]); byte generatorIdBits = byte.Parse(Configuration.GetSection("IdGen")["GeneratorIdBits"]); byte sequenceBits = byte.Parse(Configuration.GetSection("IdGen")["SequenceBits"]); // Create an ID with 45 bits for timestamp, 2 for generator-id // and 16 for sequence var structure = new IdStructure(timestampBits, generatorIdBits, sequenceBits); // Prepare options x.GeneratorOptions = new IdGeneratorOptions(structure, new DefaultTimeSource(epoch)); }); services.AddStackExchangeRedisExtensions <CacheSerializer>(conf); string connection = Configuration.GetSection("MongoPersist")["Connection"]; services.AddSingleton <MongoDB.Driver.IMongoClient>(s => new MongoDB.Driver.MongoClient(connection)); services.AddSingleton <IAccountDB, AccountDB>(); services.AddSingleton <IRealmDB, RealmDB>(); services.AddSingleton <IEntityDB, EntityDB>(); }) //need to configure a grain storage called "PubSubStore" for using streaming with ExplicitSubscribe pubsub type //.AddMemoryGrainStorage("PubSubStore") //Depends on your application requirements, you can configure your silo with other stream providers, which can provide other features, //such as persistence or recoverability. For more information, please see http://dotnet.github.io/orleans/Documentation/Orleans-Streams/Stream-Providers.html .AddSimpleMessageStreamProvider(StreamProviders.AgentProvider); var host = builder.Build(); await host.StartAsync(); return(host); }
void BuildSiloHost() { var instrumentationKey = _configuration.GetValue <string>("ApplicationInsights:InstrumentationKey"); var hostname = _configuration.GetValue <string>("HOSTNAME"); var azureStorageConnectionString = _configuration.GetValue <string>("Storage:AzureStorageConnectionString"); var redisClusteringUrl = _configuration.GetValue <string>("REDIS_URL"); var builder = new SiloHostBuilder() .ConfigureLogging(loggingBuilder => { if (!string.IsNullOrEmpty(instrumentationKey)) { loggingBuilder.AddApplicationInsights(instrumentationKey); } loggingBuilder.AddConsole(); }) // Configure ClusterId and ServiceId .Configure <ClusterOptions>(options => { options.ClusterId = "dev"; options.ServiceId = "TwitchServices"; }) .AddStartupTask <LoadConfigurationStartupTask>() .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(ChannelGrain).Assembly).WithReferences()) // Configure connectivity .ConfigureEndpoints(hostname: hostname, siloPort: 11111, gatewayPort: 30000); if (!string.IsNullOrEmpty(azureStorageConnectionString)) { builder.AddAzureTableGrainStorage("profileStore", (AzureTableStorageOptions options) => { options.ConnectionString = azureStorageConnectionString; options.TableName = "profiles"; options.UseJson = true; options.IndentJson = false; }); builder.AddAzureTableGrainStorage("channelStore", (AzureTableStorageOptions options) => { options.ConnectionString = azureStorageConnectionString; options.TableName = "channels"; options.UseJson = true; options.IndentJson = false; }); builder.AddAzureTableGrainStorage("botSettingsStore", (AzureTableStorageOptions options) => { options.ConnectionString = azureStorageConnectionString; options.TableName = "botsettings"; options.UseJson = true; options.IndentJson = false; }); builder.AddCustomCategoriesStorage("customCategoriesStore", (CustomCategoriesStorageOptions options) => { options.ConnectionString = azureStorageConnectionString; options.TableName = "customcategories"; }); } else { builder.AddMemoryGrainStorage("profileStore"); builder.AddMemoryGrainStorage("channelStore"); builder.AddMemoryGrainStorage("botSettingsStore"); builder.AddMemoryGrainStorage("customCategoriesStore"); } if (!string.IsNullOrEmpty(redisClusteringUrl)) { // Use redis clustering when available builder.UseRedisClustering(redisClusteringUrl); } else { // Use localhost clustering for a single local silo builder.UseLocalhostClustering(11111, 30000, null, "TwitchServices", "dev"); } // Temp builder.ConfigureServices((context, services) => { // Load channels and command configuration from static json file, and inject var channelsConfig = new ConfigurationBuilder().AddJsonFile("channels.json").Build(); IEnumerable <ChannelOptions> channelOptions = new List <ChannelOptions>(); channelsConfig.GetSection("channels").Bind(channelOptions); services.AddTransient <IEnumerable <ChannelOptions> >((_) => channelOptions); // Configure services services.AddHttpClient(); services.Configure <TwitchApplicationOptions>(_configuration.GetSection("twitch")); services.Configure <TwitchChatClientOptions>(_configuration.GetSection("twitch").GetSection("IrcOptions")); services.Configure <AzureGameLocalizationStoreOptions>(_configuration.GetSection("loc:azure")); services.AddSingleton <IMessageProcessor, TracingMessageProcessor>(); services.AddTransient <TwitchChatClient>(); services.AddTransient <TwitchAPIClient>(); services.AddTransient <IGDBClient>(); services.AddSingleton <IMemoryCache, MemoryCache>(); services.AddSingleton <SteamStoreClient>(); services.AddSingleton <IAuthenticated>(s => Twitch.Authenticate() .FromAppCredentials( s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientId, s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientSecret) .Build() ); services.AddTransient <ITwitchCategoryProvider, GrainTwitchCategoryProvider>(); services.AddSingleton <IGameLocalizationStore, AzureStorageGameLocalizationStore>(); services.PostConfigure <TwitchChatClientOptions>(options => { var oauth = Twitch.Authenticate() .FromOAuthToken(options.OAuthToken) .Build(); var loggerFactory = new LoggerFactory(); using (var httpClient = new HttpClient()) using (var apiClient = TwitchAPIClient.Create(oauth)) { options.TokenInfo = apiClient.ValidateToken().Result; } }); // Configure commands services.AddCommand <GameSynopsisCommand>("GameSynopsis"); services.AddCommand <TracingMessageProcessor>("Logger"); services.AddCommand <ResponseCommandProcessor>("Response"); }); _siloHost = builder.Build(); }
private static async Task <ISiloHost> CreateSilo() { var conf = new RedisConfiguration() { AbortOnConnectFail = true, Hosts = new RedisHost[] { new RedisHost { Host = Configuration.GetSection("RedisCache")["Connection"], Port = int.Parse(Configuration.GetSection("RedisCache")["Port"]) } }, AllowAdmin = true, ConnectTimeout = 1000, ServerEnumerationStrategy = new ServerEnumerationStrategy() { Mode = ServerEnumerationStrategy.ModeOptions.All, TargetRole = ServerEnumerationStrategy.TargetRoleOptions.Any, UnreachableServerAction = ServerEnumerationStrategy.UnreachableServerActionOptions.Throw } }; var builder = new SiloHostBuilder() .Configure <ClusterOptions>(options => { options.ClusterId = Configuration.GetSection("Orleans")["ClusterId"]; options.ServiceId = Configuration.GetSection("Orleans")["ServiceId"]; }) .Configure <SchedulingOptions>(options => { options.AllowCallChainReentrancy = true; options.PerformDeadlockDetection = true; }) .Configure <SerializationProviderOptions>(options => { options.SerializationProviders.Add(typeof(ProtobufNetSerializer)); options.FallbackSerializationProvider = typeof(ProtobufNetSerializer); }) .Configure <EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback) .UseMongoDBClient(Configuration.GetSection("Orleans")["Connection"]) .UseMongoDBReminders(options => { options.DatabaseName = Configuration.GetSection("Orleans")["Database"]; options.CreateShardKeyForCosmos = false; }) .UseMongoDBClustering(c => { c.DatabaseName = Configuration.GetSection("Orleans")["Database"]; c.CreateShardKeyForCosmos = false; }) .AddMongoDBGrainStorageAsDefault(c => c.Configure(options => { options.DatabaseName = Configuration.GetSection("Orleans")["Database"]; options.CreateShardKeyForCosmos = false; })) .AddMongoDBGrainStorage("PubSubStore", options => { options.DatabaseName = Configuration.GetSection("Orleans")["Database"]; options.CreateShardKeyForCosmos = false; }) .ConfigureLogging(builder => { builder.AddSerilog(new LoggerConfiguration() .ReadFrom.Configuration(Configuration) .CreateLogger()); }) .AddStartupTask <NStartupTask>() .ConfigureApplicationParts(parts => { parts.AddFromApplicationBaseDirectory().WithReferences(); }) //.AddApplicationPart(typeof(Node).Assembly).WithReferences()) .ConfigureServices(services => { services.AddStackExchangeRedisExtensions <ProtobufSerializer>(conf); string connection = Configuration.GetSection("MongoPersist")["Connection"]; services.AddSingleton <MongoDB.Driver.IMongoClient>(s => new MongoDB.Driver.MongoClient(connection)); }) //need to configure a grain storage called "PubSubStore" for using streaming with ExplicitSubscribe pubsub type //.AddMemoryGrainStorage("PubSubStore") //Depends on your application requirements, you can configure your silo with other stream providers, which can provide other features, //such as persistence or recoverability. For more information, please see http://dotnet.github.io/orleans/Documentation/Orleans-Streams/Stream-Providers.html .AddSimpleMessageStreamProvider(StreamProviders.AgentProvider); var host = builder.Build(); await host.StartAsync(); return(host); }
/// <summary> /// A method to build Orleans host. /// </summary> /// <param name="args">The arguments to use to build the host.</param> /// <returns>A built Orleans silo host.</returns> public static ISiloHost BuildOrleansHost(string[] args, ClusterConfig clusterConfig) { var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.orleanshost.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.orleanshost.{environmentName}.json", optional: false, reloadOnChange: true) .AddEnvironmentVariables() .AddCommandLine(args ?? Array.Empty <string>()) .AddInMemoryCollection() .Build(); //If cluster configuration is null, the application is likely started from the command line, //so try read one from a JSON configuration file. Also, test sets args == null. if (clusterConfig == null) { clusterConfig = configuration.GetSection("ClusterConfig").Get <ClusterConfig>(); } var siloBuilder = new SiloHostBuilder() .ConfigureLogging((hostingContext, logging) => { //TODO: Logging slows down testing a bit. //logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); }) .UsePerfCounterEnvironmentStatistics() .Configure <ClusterOptions>(options => { options.ClusterId = clusterConfig.ClusterOptions.ClusterId; options.ServiceId = clusterConfig.ClusterOptions.ServiceId; }) .UseAdoNetClustering(options => { options.Invariant = clusterConfig.ConnectionConfig.AdoNetConstant; options.ConnectionString = clusterConfig.ConnectionConfig.ConnectionString; }) .Configure <EndpointOptions>(options => { options.AdvertisedIPAddress = clusterConfig.EndPointOptions.AdvertisedIPAddress ?? IPAddress.Loopback; options.GatewayListeningEndpoint = clusterConfig.EndPointOptions.GatewayListeningEndpoint; options.GatewayPort = clusterConfig.EndPointOptions.GatewayPort; options.SiloListeningEndpoint = clusterConfig.EndPointOptions.SiloListeningEndpoint; options.SiloPort = clusterConfig.EndPointOptions.SiloPort; }) .Configure <SiloMessagingOptions>(options => { options.ResponseTimeout = TimeSpan.FromSeconds(5); }) .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(TestStateGrain).Assembly).WithReferences()) .UseAdoNetReminderService(options => { options.Invariant = clusterConfig.ReminderConfigs[0].AdoNetConstant; options.ConnectionString = clusterConfig.ReminderConfigs[0].ConnectionString; }) .AddAdoNetGrainStorage(clusterConfig.StorageConfigs[0].Name, options => { options.Invariant = clusterConfig.StorageConfigs[0].AdoNetConstant; options.ConnectionString = clusterConfig.StorageConfigs[0].ConnectionString; }); return(siloBuilder.Build()); }
private static async Task <ISiloHost> StartSilo() { var config = LoadConfig(); var orleansConfig = GetOrleansConfig(config); var builder = new SiloHostBuilder() // Clustering information .Configure <ClusterOptions>(options => { // unique ID for the orleans cluster options.ClusterId = "dev"; // unique Id for our app // not change across deployment options.ServiceId = "HelloApp"; }) // Clustering provider .UseLocalhostClustering() .UseDashboard() .ConfigureServices(services => { services.AddSingleton(s => CreateGrainMethodsList()); services.AddSingleton(s => new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None, TypeNameHandling = TypeNameHandling.None, ReferenceLoopHandling = ReferenceLoopHandling.Serialize, PreserveReferencesHandling = PreserveReferencesHandling.Objects }); services.AddSingleton <IOrleansRequestContext, OrleansRequestContext>(); }) .AddStateStorageBasedLogConsistencyProvider() .AddIncomingGrainCallFilter <LoggingFilter>() // Endpoints .Configure <EndpointOptions>(options => { // silo to silo options.SiloPort = 11111; // silo to client at the same cluster options.GatewayPort = 30000; options.AdvertisedIPAddress = IPAddress.Loopback; }) .AddAdoNetGrainStorageAsDefault(options => { options.Invariant = orleansConfig.Invariant; options.ConnectionString = orleansConfig.ConnectionString; options.UseJsonFormat = true; }) .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(HelloGrain).Assembly).WithReferences()) .ConfigureLogging(logging => logging .AddFilter("Microsoft", LogLevel.Warning) .AddFilter("System", LogLevel.Warning) .AddConsole()); var host = builder.Build(); await host.StartAsync(); return(host); }
private static async Task <ISiloHost> StartSilo() { Console.WriteLine(IPAddress.Loopback); var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .Build(); var invariant = "System.Data.SqlClient"; var connectionString = config.GetConnectionString("DefaultConnectionString"); var assambly = typeof(ISettlementGrain).Assembly; var builder = new SiloHostBuilder() .Configure <ClusterOptions>(options => { options.ClusterId = config.GetSection("Cluster").GetSection("ClusterID").Value; options.ServiceId = config.GetSection("Cluster").GetSection("ServiceID").Value; }) //.UseLocalhostClustering() //.ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000) .Configure <EndpointOptions>(options => { //配置本地套节字 options.SiloPort = 11111; options.GatewayPort = 30000; options.AdvertisedIPAddress = IPAddress.Parse(config.GetSection("IP").Value); }) .ConfigureApplicationParts(parts => parts.AddApplicationPart(assambly).WithReferences()) .ConfigureLogging(logging => logging.AddConsole()) .AddLogStorageBasedLogConsistencyProvider("LogStorage") .AddStateStorageBasedLogConsistencyProvider("StateStorage") .ConfigureAppConfiguration(context => { context.AddConfiguration(config); }) // .UseInMemoryReminderService() //依赖注入 .UseServiceProviderFactory(opt => { opt.AddTransient <ISettlementRepository, SettlementRepository>(); return(opt.BuildServiceProvider()); }) //use AdoNet for clustering .UseAdoNetClustering(options => { options.Invariant = invariant; options.ConnectionString = connectionString; }) //use AdoNet for reminder service .UseAdoNetReminderService(options => { options.Invariant = invariant; options.ConnectionString = connectionString; }) //use AdoNet for Persistence .AddAdoNetGrainStorage("SettlementStore", options => { options.UseJsonFormat = true; options.Invariant = invariant; options.ConnectionString = connectionString; }); var host = builder.Build(); await host.StartAsync(); return(host); }
static void Main(string[] args) { //request node number int siloPort = 0; int gatewayPort = 0; string serviceId = ""; //Get config from command line if (args.Length == 3) { int.TryParse(args[0], out siloPort); int.TryParse(args[1], out gatewayPort); serviceId = args[2]; } //IF not provided by command line, ask keuboard input if (siloPort == 0) { Console.WriteLine("Enter the node number:"); switch (Console.ReadKey().KeyChar) { case '1': siloPort = 10000; gatewayPort = 10002; serviceId = "SouthPark1"; break; case '2': siloPort = 20000; gatewayPort = 20002; serviceId = "SouthPark2"; break; case '3': siloPort = 30000; gatewayPort = 30002; serviceId = "SouthPark3"; break; default: return; } } //Write out configuration information FluentColorConsole.ColorConsole.WithYellowBackground.AndBlackText.WriteLine($"Silo port: {siloPort}, Gateway port {gatewayPort}, Sile name {serviceId}"); //Build connection string SqlConnectionStringBuilder connstring = new SqlConnectionStringBuilder(); connstring.DataSource = @".\MSSQLSERVER2017"; connstring.InitialCatalog = "SouthPark"; connstring.IntegratedSecurity = true; string invariant = "System.Data.SqlClient"; //define the cluster configuration var builder = new SiloHostBuilder() .UseLocalhostClustering() .Configure <ClusterOptions>(options => { options.ClusterId = "SouthParkCluster"; options.ServiceId = serviceId; }) .UseAdoNetClustering(options => { options.ConnectionString = connstring.ConnectionString; options.Invariant = invariant; }) .AddAdoNetGrainStorage("LocalSql", options => { options.ConnectionString = connstring.ConnectionString; options.Invariant = invariant; options.UseJsonFormat = true; }) .Configure <EndpointOptions>(options => { options.SiloPort = siloPort; options.GatewayPort = gatewayPort; options.AdvertisedIPAddress = IPAddress.Loopback; }) .ConfigureLogging(logging => logging.AddConsole()); //build the silo var host = builder.Build(); //start the silo var startTask = host.StartAsync(); Console.ReadKey(); }
private static async Task <ISiloHost> StartSilo() { IConfiguration hostConfig = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddIniFile(Path.Combine("init", "HostConfig.ini"), optional: false, reloadOnChange: false) .AddIniFile(Path.Combine("init", "DashboardConfig.ini"), optional: false, reloadOnChange: false) .Build(); var builder = new SiloHostBuilder() .UseDashboard() // .UseDashboard(options => // { // options.Username = "******"; // options.Password = "******"; // options.Host = "*"; // options.Port = 20020; // options.HostSelf = true; // }) .AddAdoNetGrainStorageAsDefault(op => { op.ConnectionString = "Data Source=10.0.113.10;Initial Catalog=OrleansStore_ZC;Persist Security Info=True;User ID=sa;Password=admin@2023"; op.UseJsonFormat = true; }) .UseLocalhostClustering() .AddLogStorageBasedLogConsistencyProvider("LogStorage") .AddStateStorageBasedLogConsistencyProvider("StateStorage") .AddCustomStorageBasedLogConsistencyProvider("CustomStorage") // .AddMemoryGrainStorage("DevStore") // .AddMemoryGrainStorageAsDefault() .UseInMemoryReminderService() // .AddStartupTask<GenChangeTask>(20000) .AddStartupTask <GetTopChangeTask>(30000) .AddStartupTask <GetAllChangeTask>(40000) .AddStartupTask <GetCurrentTask>(50000) .Configure <DashboardOptions>(hostConfig.GetSection("DashboardOptions")) .Configure <SiloOptions>(opt => opt.SiloName = Dns.GetHostName()) .Configure <ClusterOptions>(hostConfig.GetSection("ClusterOptions")) .Configure <EndpointOptions>(hostConfig.GetSection("EndpointOptions")) .Configure <DevelopmentClusterMembershipOptions>(hostConfig.GetSection("DevelopmentClusterMembershipOptions")) // .ConfigureServices((ctx, ss) => // { // ss.Configure<DevelopmentClusterMembershipOptions>(hostConfig.GetSection("DevelopmentClusterMembershipOptions")); // }) .ConfigureApplicationParts(parts => parts // .AddApplicationPart(typeof(HelloGrain).Assembly) .AddFromApplicationBaseDirectory() .WithCodeGeneration() // .AddFromApplicationBaseDirectory() //.WithReferences() ) .ConfigureLogging(logging => logging .AddFilter("Orleans", LogLevel.Error) .AddFilter("Orleans.Runtime.Management", LogLevel.Error) .AddFilter("Orleans.Runtime.SiloControl", LogLevel.Error) .AddFilter("Runtime", LogLevel.Error) .AddFilter("GrainImplement.LogStorageBasedEventGrain", LogLevel.None) .AddFilter("GrainImplement.StateStorageBasedEventGrain", LogLevel.None) .AddFilter("GrainImplement.CustomStorageBasedEventGrain", LogLevel.Information) .AddFilter("MySiloHost.StartupTasks", LogLevel.Information) .SetMinimumLevel(LogLevel.None) .AddConsole()); var host = builder.Build(); await host.StartAsync(); return(host); }
private static async Task <ISiloHost> StartSilo() { var baseDir = Path.Combine(AppContext.BaseDirectory); Configuration = AppConfiguration.GetIConfigurationRoot(baseDir); var appOptions = AppConfiguration.GetApplicationConfiguration(baseDir); var dashboardOptions = AppConfiguration.GetConfiguration <DashboardOptions>(baseDir, "Dashboard"); // define the cluster configuration var builder = new SiloHostBuilder(); switch (appOptions.StorageType) { case StorageType.AzureTable: builder.AddAzureTableGrainStorage(Constants.StorageName, options => { options.ConnectionString = appOptions.OrleansConnectionString; options.TableName = appOptions.AzureTableName; options.UseJson = appOptions.UseJson; }); builder.UseAzureTableReminderService(options => { options.ConnectionString = appOptions.OrleansConnectionString; }); break; default: builder.AddAdoNetGrainStorage(Constants.StorageName, options => { options.Invariant = appOptions.AdoInvariant; options.ConnectionString = appOptions.OrleansConnectionString; options.UseJsonFormat = appOptions.UseJson; }); builder.UseAdoNetReminderService(options => { options.ConnectionString = appOptions.OrleansConnectionString; }); break; } builder.UseLocalhostClustering() .Configure <ClusterOptions>(options => { options.ClusterId = appOptions.ClusterId; options.ServiceId = appOptions.ServiceId; }) .Configure <EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback) .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IGrainMarker).Assembly).WithReferences()) .AddSimpleMessageStreamProvider(Constants.StreamProvider) .AddMemoryGrainStorage(Constants.StreamStorage) .ConfigureServices((service) => { service.Configure <ApplicationOptions>(Configuration); service.AddOptions(); service.AddSingleton <ApplicationOptions>(appOptions); DependencyInjectionHelper.IocContainerRegistration(service); }) .ConfigureLogging(logging => logging.AddConsole()) .UseDashboard(options => { options.Host = dashboardOptions.Host; options.Port = dashboardOptions.Port; options.HostSelf = dashboardOptions.HostSelf; options.CounterUpdateIntervalMs = dashboardOptions.CounterUpdateIntervalMs; }); var host = builder.Build(); await host.StartAsync(); return(host); }
private static async Task <ISiloHost> StartSilo() { IConfiguration hostConfig = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddIniFile(Path.Combine("init", "HostConfig.ini"), optional: false, reloadOnChange: false) .AddIniFile(Path.Combine("init", "DashboardConfig.ini"), optional: false, reloadOnChange: false) .Build(); var builder = new SiloHostBuilder() .UseDashboard() // .UseDashboard(options => // { // options.Username = "******"; // options.Password = "******"; // options.Host = "*"; // options.Port = 20020; // options.HostSelf = true; // }) // .UseLocalhostClustering() .UseConsulClustering(op => { op.Address = new Uri("http://127.0.0.1:8500"); }) .AddMemoryGrainStorage("DevStore") //.AddMemoryGrainStorageAsDefault() .UseInMemoryReminderService() .AddSimpleMessageStreamProvider("SMSProvider", op => { op.FireAndForgetDelivery = SimpleMessageStreamProviderOptions.DEFAULT_VALUE_FIRE_AND_FORGET_DELIVERY; op.OptimizeForImmutableData = SimpleMessageStreamProviderOptions.DEFAULT_VALUE_OPTIMIZE_FOR_IMMUTABLE_DATA; op.PubSubType = SimpleMessageStreamProviderOptions.DEFAULT_PUBSUB_TYPE; }) // .AddPersistentStreams("SMSProvider_Persistent", (services, name) => // { // return null; // }, streamConfigurator => // { // }) .AddStartupTask <FirstStartupTask>() .AddMemoryGrainStorage("PubSubStore") .Configure <DashboardOptions>(hostConfig.GetSection("DashboardOptions")) .Configure <SiloOptions>(opt => opt.SiloName = Dns.GetHostName()) .Configure <ClusterOptions>(hostConfig.GetSection("ClusterOptions")) .Configure <EndpointOptions>(hostConfig.GetSection("EndpointOptions")) .Configure <DevelopmentClusterMembershipOptions>(hostConfig.GetSection("DevelopmentClusterMembershipOptions")) .Configure <ConsulClusteringSiloOptions>(hostConfig.GetSection("ConsulClusteringSiloOptions")) // .ConfigureServices((ctx, ss) => // { // ss.Configure<DevelopmentClusterMembershipOptions>(hostConfig.GetSection("DevelopmentClusterMembershipOptions")); // }) // .Configure<MemoryGrainStorageOptions>(hostConfig) .ConfigureApplicationParts(parts => parts // .AddApplicationPart(typeof(HelloGrain).Assembly) .AddFromApplicationBaseDirectory() .WithCodeGeneration() // .AddFromApplicationBaseDirectory() //.WithReferences() ) .ConfigureLogging(logging => logging .AddFilter("Orleans", LogLevel.Warning) // .AddFilter("Orleans.Runtime.Management", LogLevel.Warning) // .AddFilter("Orleans.Runtime.SiloControl", LogLevel.Warning) // .AddFilter("Runtime", LogLevel.Warning) .SetMinimumLevel(LogLevel.Debug) .AddConsole()); var host = builder.Build(); await host.StartAsync(); return(host); }
private static async Task <ISiloHost> StartSilo() { var builder = new SiloHostBuilder() .UseLocalhostClustering() .UseDashboard() .AddRay <Configuration>() .Configure <EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback) .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(Account).Assembly).WithReferences()) .ConfigureServices((context, servicecollection) => { //注册postgresql为事件存储库 //servicecollection.AddPostgreSQLStorage(config => //{ // config.ConnectionDict.Add("core_event", "Server=127.0.0.1;Port=5432;Database=Ray;User Id=postgres;Password=extop;Pooling=true;MaxPoolSize=20;"); //}); //servicecollection.AddPostgreSQLTxStorage(options => //{ // options.ConnectionKey = "core_event"; // options.TableName = "Transaction_TemporaryRecord"; //}); //servicecollection.PSQLConfigure(); servicecollection.AddSQLServerStorage(config => { config.ConnectionDict.Add("core_event", "Server=127.0.0.1,1444;Database=Ray;User Id=sa;Password=a8744965;Pooling=true;max pool size=20;"); //config.ConnectionDict.Add("core_event", "Server=127.0.0.1,1444;Database=Ray1;User Id=sa;Password=a8744965;Pooling=true;max pool size=20;"); }); servicecollection.AddSQLServerTxStorage(options => { options.ConnectionKey = "core_event"; options.TableName = "Transaction_TemporaryRecord"; }); servicecollection.SQLServerConfigure(); //注册mysql作为事件存储库 //servicecollection.AddMySQLStorage(config => //{ // config.ConnectionDict.Add("core_event", "Server=127.0.0.1;Port=3306;Database=ray;User Id=root;Password=extop;Pooling=true;MaxPoolSize=20;"); //}); //servicecollection.AddMySQLTxStorage(options => //{ // options.ConnectionKey = "core_event"; // options.TableName = "Transaction_TemporaryRecord"; //}); //servicecollection.MySQLConfigure(); //注册mongodb为事件存储库 //servicecollection.AddMongoDBStorage(config => //{ // config.ConnectionDict.Add("core", "mongodb://127.0.0.1:27017"); //}); //servicecollection.AddMongoTransactionStorage(options => //{ // options.ConnectionKey = "core"; // options.CollectionName = "Transaction_TemporaryRecord"; //}); //servicecollection.MongoConfigure(); servicecollection.AddRabbitMQ(config => { config.UserName = "******"; config.Password = "******"; config.Hosts = new[] { "127.0.0.1:5672" }; config.MaxPoolSize = 100; config.VirtualHost = "/"; }); //servicecollection.AddKafkaMQ( // config => { }, // config => // { // config.BootstrapServers = "192.168.1.2:9092"; // }, config => // { // config.BootstrapServers = "192.168.1.2:9092"; // }, async container => // { // await container.CreateEventBus<Account>(nameof(Account), 5).DefaultConsumer<long>(); // }); //servicecollection.AddRabbitMQ(config => //{ // config.UserName = "******"; // config.Password = "******"; // config.Hosts = new[] { "127.0.0.1:5672" }; // config.MaxPoolSize = 100; // config.VirtualHost = "/"; //}, async container => //{ // await container.CreateEventBus<Account>("Account", "account", 5).DefaultConsumer<long>(); //}); }) .Configure <GrainCollectionOptions>(options => { options.CollectionAge = TimeSpan.FromMinutes(5); }) .ConfigureLogging(logging => { logging.SetMinimumLevel(LogLevel.Information); logging.AddConsole(options => options.IncludeScopes = true); }); var host = builder.Build(); await host.StartAsync(); return(host); }
/// <summary> /// Создаем Silo для Orleans. /// /// </summary> /// <returns></returns> public static ISiloHost BuildOrleansHost() { //Стандартный сопсоб считывать настройки из разных файлов конфигшуроации //в зависимости от переменной окружания (Development, production и пр.) var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.orleanshost.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.orleanshost.{environmentName}.json", optional: false, reloadOnChange: true) .AddInMemoryCollection() .Build(); //Читаем настройки из файла var clusterConfig = configuration.GetSection("ClusterConfig").Get <ClusterConfig>(); var siloBuilder = new SiloHostBuilder() .ConfigureLogging((hostingContext, logging) => { logging.AddConsole(); logging.AddDebug(); }) .UsePerfCounterEnvironmentStatistics() //Используем системные счетчики для статистики работы кластера .Configure <ClusterOptions>(options => { options.ClusterId = clusterConfig.ClusterOptions.ClusterId; options.ServiceId = clusterConfig.ClusterOptions.ServiceId; }) //Альтернативно можем использовать Azure Tables, например. .UseAdoNetClustering(options => { options.Invariant = clusterConfig.ConnectionConfig.AdoNetConstant; options.ConnectionString = clusterConfig.ConnectionConfig.ConnectionString; }) .Configure <EndpointOptions>(options => { //Если IP кластера не задан, то исполььузем LoopBack options.AdvertisedIPAddress = clusterConfig.EndPointOptions.AdvertisedIPAddress ?? IPAddress.Loopback; options.GatewayListeningEndpoint = clusterConfig.EndPointOptions.GatewayListeningEndpoint; options.GatewayPort = clusterConfig.EndPointOptions.GatewayPort; options.SiloListeningEndpoint = clusterConfig.EndPointOptions.SiloListeningEndpoint; options.SiloPort = clusterConfig.EndPointOptions.SiloPort; }) .Configure <SiloMessagingOptions>(options => { options.ResponseTimeout = TimeSpan.FromSeconds(5); //options.ResendOnTimeout = true; Убрано в 3.0 //options.MaxResendCount = 5; }) .UseAdoNetReminderService(options => { options.Invariant = clusterConfig.ReminderConfigs[0].AdoNetConstant; options.ConnectionString = clusterConfig.ReminderConfigs[0].ConnectionString; }) .AddAdoNetGrainStorage(clusterConfig.StorageConfigs[0].Name, options => { options.Invariant = clusterConfig.StorageConfigs[0].AdoNetConstant; options.ConnectionString = clusterConfig.StorageConfigs[0].ConnectionString; }) //Тут добавялем источники загрузки наших Grain'ов. Не заюываем подключить пространство имен "Orleans" :) .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(UserGrain).Assembly).WithReferences()); return(siloBuilder.Build()); }
public SiloWrapper(IConfiguration config, ISemanticLog log, IApplicationLifetime 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> >() .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); }); }