Orleans Przegląd cyklu życia silosu
Orleans Silosy używają zauważalnego cyklu życia do uporządkowanego uruchamiania i zamykania Orleans systemów, a także składników warstwy aplikacji. Aby uzyskać więcej informacji na temat szczegółów implementacji, zobacz Orleans cykl życia.
Etapy
Orleans Klienci silosu i klastra używają wspólnego zestawu etapów cyklu życia usługi.
public static class ServiceLifecycleStage
{
public const int First = int.MinValue;
public const int RuntimeInitialize = 2_000;
public const int RuntimeServices = 4_000;
public const int RuntimeStorageServices = 6_000;
public const int RuntimeGrainServices = 8_000;
public const int ApplicationServices = 10_000;
public const int BecomeActive = Active - 1;
public const int Active = 20_000;
public const int Last = int.MaxValue;
}
- ServiceLifecycleStage.First: pierwszy etap cyklu życia usługi.
- ServiceLifecycleStage.RuntimeInitialize: Inicjowanie środowiska uruchomieniowego, w którym silos inicjuje wątki.
- ServiceLifecycleStage.RuntimeServices: Początek usług środowiska uruchomieniowego, w którym silos inicjuje sieć i różnych agentów.
- ServiceLifecycleStage.RuntimeStorageServices: Inicjowanie magazynu środowiska uruchomieniowego.
- ServiceLifecycleStage.RuntimeGrainServices: Początek usług środowiska uruchomieniowego dla ziarna. Obejmuje to zarządzanie typami ziarna, usługę członkostwa i katalog ziarna.
- ServiceLifecycleStage.ApplicationServices: usługi warstwy aplikacji.
- ServiceLifecycleStage.BecomeActive: silos dołącza do klastra.
- ServiceLifecycleStage.Active: Silos jest aktywny w klastrze i gotowy do akceptowania obciążenia.
- ServiceLifecycleStage.Last: ostatni etap cyklu życia usługi.
Rejestrowanie
Ze względu na inwersję kontroli, gdzie uczestnicy dołączają do cyklu życia, a nie cyklu życia, który ma jakiś scentralizowany zestaw kroków inicjowania, nie zawsze jest jasne z kodu, czym jest kolejność uruchamiania/zamykania. Aby rozwiązać ten problem, rejestrowanie zostało dodane przed uruchomieniem silosu, aby zgłosić, jakie składniki uczestniczą na każdym etapie. Te dzienniki są rejestrowane na poziomie dziennika informacji w rejestratorze Orleans.Runtime.SiloLifecycleSubject . Przykład:
Information, Orleans.Runtime.SiloLifecycleSubject, "Stage 2000: Orleans.Statistics.PerfCounterEnvironmentStatistics, Orleans.Runtime.InsideRuntimeClient, Orleans.Runtime.Silo"
Information, Orleans.Runtime.SiloLifecycleSubject, "Stage 4000: Orleans.Runtime.Silo"
Information, Orleans.Runtime.SiloLifecycleSubject, "Stage 10000: Orleans.Runtime.Versions.GrainVersionStore, Orleans.Storage.AzureTableGrainStorage-Default, Orleans.Storage.AzureTableGrainStorage-PubSubStore"
Ponadto informacje o chronometrażu i błędzie są podobnie rejestrowane dla każdego składnika według etapu. Przykład:
Information, Orleans.Runtime.SiloLifecycleSubject, "Lifecycle observer Orleans.Runtime.InsideRuntimeClient started in stage 2000 which took 33 Milliseconds."
Information, Orleans.Runtime.SiloLifecycleSubject, "Lifecycle observer Orleans.Statistics.PerfCounterEnvironmentStatistics started in stage 2000 which took 17 Milliseconds."
Udział w cyklu życia silosu
Logika aplikacji może wziąć udział w cyklu życia silosu, rejestrując uczestniczącą usługę w kontenerze usługi silosu. Usługa musi być zarejestrowana jako element , gdzie ILifecycleParticipant<TLifecycleObservable> T
to ISiloLifecycle.
public interface ISiloLifecycle : ILifecycleObservable
{
}
public interface ILifecycleParticipant<TLifecycleObservable>
where TLifecycleObservable : ILifecycleObservable
{
void Participate(TLifecycleObservable lifecycle);
}
Po uruchomieniu silosu wszyscy uczestnicy (ILifecycleParticipant<ISiloLifecycle>
) w kontenerze będą mogli uczestniczyć przez wywołanie ich ILifecycleParticipant<TLifecycleObservable>.Participate zachowania. Gdy wszyscy mieli okazję uczestniczyć, obserwowany cykl życia silosu rozpocznie wszystkie etapy w kolejności.
Przykład
Wraz z wprowadzeniem cyklu życia silosu dostawcy bootstrap, którzy umożliwiali deweloperom aplikacji wstrzykiwanie logiki w fazie inicjowania dostawcy, nie są już niezbędne, ponieważ logika aplikacji może być teraz wstrzykiwana na dowolnym etapie uruchamiania silosu. Niemniej jednak dodaliśmy fasadę "zadania startowego", aby pomóc w przejściu dla deweloperów, którzy korzystali z dostawców bootstrap. Jako przykład sposobu opracowywania składników, które biorą udział w cyklu życia silosu, przyjrzymy się fasadzie zadania uruchamiania.
Zadanie uruchamiania musi dziedziczyć tylko z ILifecycleParticipant<ISiloLifecycle>
i subskrybować logikę aplikacji do cyklu życia silosu na określonym etapie.
class StartupTask : ILifecycleParticipant<ISiloLifecycle>
{
private readonly IServiceProvider _serviceProvider;
private readonly Func<IServiceProvider, CancellationToken, Task> _startupTask;
private readonly int _stage;
public StartupTask(
IServiceProvider serviceProvider,
Func<IServiceProvider, CancellationToken, Task> startupTask,
int stage)
{
_serviceProvider = serviceProvider;
_startupTask = startupTask;
_stage = stage;
}
public void Participate(ISiloLifecycle lifecycle)
{
lifecycle.Subscribe<StartupTask>(
_stage,
cancellation => _startupTask(_serviceProvider, cancellation));
}
}
Z powyższej implementacji widać, że w Participate(...)
wywołaniu subskrybuje cykl życia silosu na skonfigurowanym etapie, przekazując wywołanie zwrotne aplikacji, a nie logikę inicjowania. Składniki, które muszą zostać zainicjowane na danym etapie, zapewnią wywołanie zwrotne, ale wzorzec jest taki sam. Teraz, gdy mamy element StartupTask
, który zapewni, że punkt zaczepienia aplikacji jest wywoływany na skonfigurowanym etapie, musimy upewnić się, że udział StartupTask
w cyklu życia silosu.
W tym celu musimy zarejestrować go tylko w kontenerze. Robimy to za pomocą funkcji rozszerzenia w pliku ISiloHostBuilder:
public static ISiloHostBuilder AddStartupTask(
this ISiloHostBuilder builder,
Func<IServiceProvider, CancellationToken, Task> startupTask,
int stage = ServiceLifecycleStage.Active)
{
builder.ConfigureServices(services =>
services.AddTransient<ILifecycleParticipant<ISiloLifecycle>>(
serviceProvider =>
new StartupTask(
serviceProvider, startupTask, stage)));
return builder;
}
Rejestrując startupTask w kontenerze usługi silosu jako interfejs ILifecycleParticipant<ISiloLifecycle>
znacznika, ten sygnał silosowi musi wziąć udział w cyklu życia silosu.