Sdílet prostřednictvím


Časovače a připomenutí

Modul Orleans runtime poskytuje dva mechanismy označované jako časovače a připomenutí, které vývojářům umožňují určit pravidelné chování zrn.

Časovače

Časovače se používají k vytváření pravidelného chování agregačního intervalu, které není potřeba k rozprostření více aktivací (vytvoření instance zrnka). Časovač je shodný se standardní třídou .NET System.Threading.Timer . Kromě toho časovače podléhají zárukám jednovláknového provedení v rámci aktivace jádra, na které pracují.

Každá aktivace může mít přiřazených nula nebo více časovačů. Modul runtime spustí každou rutinu časovače v kontextu modulu runtime aktivace, ke které je přidružená.

Využití časovače

Pokud chcete spustit časovač, použijte metodu RegisterGrainTimerIGrainTimer , která vrací odkaz:

protected IGrainTimer RegisterGrainTimer<TState>(
    Func<TState, CancellationToken, Task> callback, // function invoked when the timer ticks
    TState state,                                   // object to pass to callback
    GrainTimerCreationOptions options)              // timer creation options

Pokud chcete časovač zrušit, odstraňte ho.

Časovač přestane spouštět, pokud se agregační interval deaktivuje nebo když dojde k chybě a dojde k chybovému ukončení jeho sila.

Důležité aspekty:

  • Pokud je povolená aktivační kolekce, spuštění zpětného volání časovače nezmění stav aktivace z nečinnosti na použití. To znamená, že časovač nelze použít k odložení deaktivace jinak nečinných aktivací.
  • Uplynulé období Grain.RegisterGrainTimer je doba, která uplynula od okamžiku Task , kdy je vrácena callback , vyřešena až do okamžiku, kdy by mělo dojít k dalšímu callback vyvolání. To nejen znemožňuje následným voláním callback překrývat se, ale také umožňuje, aby doba callback trvání dokončení ovlivnila frekvenci, při které callback je vyvolána. To je důležitá odchylka od sémantiky System.Threading.Timer.
  • Každé vyvolání callback se doručí do aktivace na samostatném turnu a nikdy neběží souběžně s jinými zapnutími stejné aktivace.
  • Zpětná volání se ve výchozím nastavení neprolínají. Prokládání je možné povolit nastavením možnosti Interleave na hodnotu true u GrainTimerCreationOptions.
  • Časovače lze aktualizovat pomocí metody Change(TimeSpan, TimeSpan) u vrácené instance IGrainTimer.
  • Zpětná volání mohou udržovat zrno aktivní, čímž se zabrání jeho uvolnění, pokud je období časovače relativně krátké. To je možné povolit nastavením KeepAlive na true u GrainTimerCreationOptions.
  • Zpětná volání mohou obdržet token zrušení, který se zruší, když je časovač likvidován nebo když se objekt začne deaktivovat.
  • Zpětná volání mohou uvolnit časovač zrna, který je spustil.
  • Zpětná volání podléhají filtrům jemnosti volání.
  • Zpětná volání jsou viditelná v distribuovaném trasování, pokud je povolené distribuované trasování.
  • Třídy POCO (třídy, které nedědí z Grain) mohou registrovat časovače zrn pomocí metody rozšíření RegisterGrainTimer.

Připomenutí

Připomenutí se podobají časovačům s několika důležitými rozdíly:

  • Připomenutí jsou trvalá a stále se aktivují téměř ve všech situacích (včetně částečného nebo úplného restartování clusteru), pokud se explicitně nezruší.
  • Připomenutí "definice" se zapisují do úložiště. Každý konkrétní výskyt s konkrétním časem ale není. To má vedlejší účinek, že pokud je cluster v době konkrétního zaškrtnutí připomenutí dole, zmešká se a dojde pouze k dalšímu zaškrtnutí připomenutí.
  • Připomenutí jsou přidružená k odstupňovanému intervalu, ne ke konkrétní aktivaci.
  • Pokud se k němu při odškrtnutí připomenutí nepřidružuje žádná aktivace, vytvoří se agregační interval. Pokud se aktivace stane nečinnou a deaktivuje se, připomenutí přidružené ke stejnému agregačnímu intervalu se znovu aktivuje, jakmile příště zaškrtne.
  • Doručení připomenutí probíhá prostřednictvím zprávy a podléhá stejné sémantice prokládání jako všechny ostatní metody agregace.
  • Připomenutí by se neměla používat pro časovače s vysokou frekvencí – jejich období by se mělo měřit v minutách, hodinách nebo dnech.

Konfigurace

Připomenutí, trvalá, spoléhají na fungování úložiště. Před funkcemi subsystému připomenutí musíte určit, které úložiště se má použít. To se provádí konfigurací jednoho z poskytovatelů připomenutí prostřednictvím Use{X}ReminderService rozšiřujících metod, kde X je název poskytovatele, UseAzureTableReminderServicenapříklad .

Konfigurace tabulky Azure:

// TODO replace with your connection string
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var silo = new HostBuilder()
    .UseOrleans(builder =>
    {
        builder.UseAzureTableReminderService(connectionString)
    })
    .Build();

SQL:

const string connectionString = "YOUR_CONNECTION_STRING_HERE";
const string invariant = "YOUR_INVARIANT";
var silo = new HostBuilder()
    .UseOrleans(builder =>
    {
        builder.UseAdoNetReminderService(options =>
        {
            options.ConnectionString = connectionString; // Redacted
            options.Invariant = invariant;
        });
    })
    .Build();

Pokud chcete, aby jenom zástupná implementace připomenutí fungovala, aniž byste museli nastavovat účet Azure nebo databázi SQL, získáte implementaci systému připomenutí, která je jen pro vývoj:

var silo = new HostBuilder()
    .UseOrleans(builder =>
    {
        builder.UseInMemoryReminderService();
    })
    .Build();

Důležité

Pokud máte heterogenní cluster, kde sila zpracovávají různé typy zrnek (implementují různá rozhraní), musí každý sil přidat konfiguraci pro připomenutí, i když samotný silo nezpracuje žádná připomenutí.

Použití připomenutí

Odstupňované zpracování, které používá připomenutí, musí implementovat metodu IRemindable.ReceiveReminder .

Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
    Console.WriteLine("Thanks for reminding me-- I almost forgot!");
    return Task.CompletedTask;
}

Pokud chcete zahájit připomenutí, použijte metodu Grain.RegisterOrUpdateReminderIGrainReminder , která vrací objekt:

protected Task<IGrainReminder> RegisterOrUpdateReminder(
    string reminderName,
    TimeSpan dueTime,
    TimeSpan period)
  • reminderName: je řetězec, který musí jedinečně identifikovat připomenutí v rámci rozsahu kontextového agregačního intervalu.
  • dueTime: určuje množství času čekání před vydáním prvního časovače.
  • period: určuje období časovače.

Vzhledem k tomu, že připomenutí přežijí životnost jakékoli jediné aktivace, musí být explicitně zrušena (na rozdíl od vyřazení). Připomenutí zrušíte voláním Grain.UnregisterReminder:

protected Task UnregisterReminder(IGrainReminder reminder)

Je objekt reminder popisovače vrácený objektem Grain.RegisterOrUpdateReminder.

Instance nejsou zaručené IGrainReminder , že budou platné i po dobu životnosti aktivace. Pokud chcete identifikovat připomenutí způsobem, který přetrvává, použijte řetězec obsahující název připomenutí.

Pokud máte pouze název připomenutí a potřebujete odpovídající instanci IGrainReminder, zavolejte metodu Grain.GetReminder :

protected Task<IGrainReminder> GetReminder(string reminderName)

Rozhodněte se, které použít

Doporučujeme používat časovače za následujících okolností:

  • Pokud nezáleží (nebo je žádoucí), že časovač přestane fungovat, když se aktivace deaktivuje nebo dojde k selhání.
  • Rozlišení časovače je malé (například přiměřeně vyjádřitelné v sekundách nebo minutách).
  • Zpětné volání časovače může být spuštěno nebo Grain.OnActivateAsync() při vyvolání metody agregačního intervalu.

Doporučujeme používat připomenutí za následujících okolností:

  • Když pravidelné chování potřebuje přežít aktivaci a případná selhání.
  • Provádění zřídka používaných úkolů (například přiměřeně vyjádřitelné v minutách, hodinách nebo dnech).

Kombinování časovačů a připomenutí

K dosažení cíle můžete zvážit použití kombinace připomenutí a časovačů. Pokud například potřebujete časovač s malým rozlišením, které musí přežít napříč aktivacemi, můžete použít připomenutí, které se spustí každých pět minut, jehož účelem je probudit zrno, které restartuje místní časovač, který mohl být ztracen z důvodu deaktivace.

Registrace agregačního intervalu POCO

Pokud chcete zaregistrovat časovač nebo připomenutí v agregačním intervalu POCO, implementujete IGrainBase rozhraní a vložíte ho ITimerRegistry nebo IReminderRegistry do konstruktoru zrnka.

using Orleans.Timers;

namespace Timers;

public sealed class PingGrain : IGrainBase, IPingGrain, IDisposable
{
    private const string ReminderName = "ExampleReminder";

    private readonly IReminderRegistry _reminderRegistry;

    private IGrainReminder? _reminder;

    public  IGrainContext GrainContext { get; }

    public PingGrain(
        ITimerRegistry timerRegistry,
        IReminderRegistry reminderRegistry,
        IGrainContext grainContext)
    {
        // Register timer
        timerRegistry.RegisterGrainTimer(
            grainContext,
            callback: static async (state, cancellationToken) =>
            {
                // Omitted for brevity...
                // Use state

                await Task.CompletedTask;
            },
            state: this,
            options: new GrainTimerCreationOptions
            {
                DueTime = TimeSpan.FromSeconds(3),
                Period = TimeSpan.FromSeconds(10)
            });

        _reminderRegistry = reminderRegistry;

        GrainContext = grainContext;
    }

    public async Task Ping()
    {
        _reminder = await _reminderRegistry.RegisterOrUpdateReminder(
            callingGrainId: GrainContext.GrainId,
            reminderName: ReminderName,
            dueTime: TimeSpan.Zero,
            period: TimeSpan.FromHours(1));
    }

    void IDisposable.Dispose()
    {
        if (_reminder is not null)
        {
            _reminderRegistry.UnregisterReminder(
                GrainContext.GrainId, _reminder);
        }
    }
}

Předchozí kód:

  • Definuje agregační interval POCO, který implementuje IGrainBase, IPingGraina IDisposable.
  • Zaregistruje časovač, který se vyvolá každých 10 sekund, a spustí 3 sekundy po registraci.
  • Při Ping zavolání zaregistruje připomenutí, které se vyvolá každou hodinu, a začne okamžitě po registraci.
  • Metoda Dispose zruší připomenutí, pokud je zaregistrovaná.