Megosztás a következőn keresztül:


Időzítők és emlékeztetők

A Orleans futtatókörnyezet két mechanizmust, úgynevezett időzítőket és emlékeztetőket biztosít, amelyek lehetővé teszik a fejlesztő számára a szemcsék rendszeres viselkedésének megadását.

Időzítők

Az időzítők olyan rendszeres szemcse viselkedést hoznak létre, amely nem szükséges több aktiválás (a szem példányainak) lefedéséhez. Az időzítő megegyezik a standard .NET-osztálysal System.Threading.Timer . Ezen kívül az időzítőkre egyszálas végrehajtási garanciák vonatkoznak az általuk működtetett gabona aktiválásán belül, és a végrehajtásuk más kérésekkel van összekötve, mintha az időzítő visszahívása egy szemcsés metódus volt megjelölve AlwaysInterleaveAttribute.

Minden aktiváláshoz nulla vagy több időzítő lehet társítva. A futtatókörnyezet minden időzítő rutint végrehajt az aktiválás futásidejű környezetében, amelyhez társítva van.

Időzítő használata

Időzítő indításához használja a Grain.RegisterTimer metódust, amely egy IDisposable hivatkozást ad vissza:

protected IDisposable RegisterTimer(
    Func<object, Task> asyncCallback, // function invoked when the timer ticks
    object state,                     // object to pass to asyncCallback
    TimeSpan dueTime,                 // time to wait before the first timer tick
    TimeSpan period)                  // the period of the timer

Az időzítő megszakításához törölje azt.

Az időzítő nem aktiválódik, ha a szemcse inaktiválva van, vagy ha hiba történik, és a siló összeomlik.

Fontos szempontok:

  • Ha az aktiválási gyűjtemény engedélyezve van, az időzítő visszahívásának végrehajtása nem módosítja az aktiválás állapotát tétlenségről használaton kívülire. Ez azt jelenti, hogy az időzítő nem használható az egyébként tétlen aktiválások inaktiválásának elhalasztására.
  • Az átadott Grain.RegisterTimer időszak az az időtartam, amely a feladat visszaadásának asyncCallback pillanatától a következő meghívás asyncCallback időpontjáig tart. Ez nem csak lehetetlenné teszi az egymást követő hívások asyncCallback átfedését, hanem azt is, hogy a teljes időtartam asyncCallback befolyásolja a meghívás gyakoriságát asyncCallback . Ez egy fontos eltérés a szemantikától System.Threading.Timer.
  • Az egyes meghívások asyncCallback külön fordulóban érkeznek az aktiváláshoz, és soha nem futnak egyidejűleg ugyanazon aktiválás más bekapcsolásaival. Az asyncCallback invokációk azonban nem üzenetekként érkeznek, ezért nem vonatkoznak az üzenetek közötti szemantikára. Ez azt jelenti, hogy az invokációk asyncCallback úgy viselkednek, mintha a gabona újra beléptethető volna, és más szemcsekérésekkel egyidejűleg hajtanak végre. A gabona kérésütemezési szemantikájának használatához meghívhat egy gabonametódust a benne asyncCallbackelvégzett munka végrehajtásához. Egy másik alternatíva egy AsyncLock vagy egy SemaphoreSlim. Részletesebb magyarázat a GitHub 2574-ik számában Orleans érhető el.

Emlékeztetők

Az emlékeztetők hasonlóak az időzítőkhöz, néhány fontos különbséggel:

  • Az emlékeztetők állandóak, és szinte minden esetben aktiválódnak (beleértve a részleges vagy teljes fürt újraindítását is), kivéve, ha explicit módon lemondják.
  • Az emlékeztető "definíciói" a tárolóba vannak írva. Az egyes előfordulások azonban nem az adott időponttal együtt. Ennek az a mellékhatása, hogy ha a fürt egy adott emlékeztetőjel időpontjában nem működik, akkor a rendszer kihagyja, és csak az emlékeztető következő osztásjele történik meg.
  • Az emlékeztetők egy szemcséhez vannak társítva, nem egy adott aktiváláshoz.
  • Ha egy szemcse nem rendelkezik aktiválással, amikor egy emlékeztető ketyeg, a szemcse létrejön. Ha egy aktiválás tétlenné válik, és inaktiválva van, az ugyanahhoz a szemhez társított emlékeztető újraaktiválja a szemcsét, amikor a következő ketyeg.
  • Az emlékeztető kézbesítése üzenetben történik, és ugyanolyan összefüggő szemantikára vonatkozik, mint az összes többi szemantika.
  • Az emlékeztetőket nem szabad nagy gyakoriságú időzítőkhöz használni, az időtartamukat percekben, órákban vagy napokban kell mérni.

Konfiguráció

Az emlékeztetők állandóak, és a tárolásra támaszkodnak a működéshez. Meg kell adnia, hogy az emlékeztető alrendszer működése előtt melyik tárterület-háttérrendszert kell használnia. Ez az emlékeztetőszolgáltatók egyikének bővítménymetelyekkel Use{X}ReminderService történő konfigurálásával történik, ahol X például UseAzureTableReminderServicea szolgáltató neve szerepel.

Azure Table-konfiguráció:

// 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();

Ha csak azt szeretné, hogy az emlékeztetők helyőrző implementációja úgy működjön, hogy nincs szükség Azure-fiók vagy SQL-adatbázis beállítására, akkor ez az emlékeztetőrendszer csak fejlesztési célú implementációját biztosítja:

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

Emlékeztetők használata

Az emlékeztetőket használó szemcséknek implementálniuk kell a metódust IRemindable.ReceiveReminder .

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

Emlékeztető indításához használja a Grain.RegisterOrUpdateReminder metódust, amely egy objektumot IGrainReminder ad vissza:

protected Task<IGrainReminder> RegisterOrUpdateReminder(
    string reminderName,
    TimeSpan dueTime,
    TimeSpan period)
  • reminderName: olyan sztring, amely egyedileg azonosítja az emlékeztetőt a környezetfüggő szemcse hatókörén belül.
  • dueTime: megadja, hogy mennyi ideig kell várni az első időzítőjel kiadása előtt.
  • period: az időzítő időtartamát adja meg.

Mivel az emlékeztetők túlélik az egyetlen aktiválás élettartamát, explicit módon le kell mondani őket (a törlés helyett). Az emlékeztetőt a következő hívással Grain.UnregisterReminderszakíthatja meg:

protected Task UnregisterReminder(IGrainReminder reminder)

Ez reminder az a leíróobjektum, amelyet Grain.RegisterOrUpdateRemindera függvény visszaadott.

A példányok IGrainReminder nem garantáltan érvényesek az aktiválás élettartamán túl. Ha egy emlékeztetőt olyan módon szeretne azonosítani, amely megmarad, használjon egy sztringet, amely az emlékeztető nevét tartalmazza.

Ha csak az emlékeztető nevét használja, és a megfelelő példányra IGrainRemindervan szüksége, hívja meg a metódust Grain.GetReminder :

protected Task<IGrainReminder> GetReminder(string reminderName)

Döntse el, hogy melyiket használja

Javasoljuk, hogy az alábbi esetekben használjon időzítőket:

  • Ha nem számít (vagy kívánatos), hogy az időzítő az aktiválás inaktiválásakor vagy meghibásodása esetén megszűnik.
  • Az időzítő felbontása kicsi (például másodpercben vagy percben kifejezhető).
  • Az időzítő visszahívása elindítható egy gabonametódus meghívásával Grain.OnActivateAsync() vagy meghívásával.

Javasoljuk, hogy az alábbi esetekben használjon emlékeztetőket:

  • Ha az időszakos viselkedésnek túl kell élnie az aktiválást és az esetleges hibákat.
  • Ritkán (például percekben, órákban vagy napokban kifejezhető) feladatok végrehajtása.

Időzítők és emlékeztetők egyesítése

Érdemes lehet emlékeztetők és időzítők kombinációját használni a cél eléréséhez. Ha például egy kis felbontású időzítőre van szüksége, amelynek az aktiválások során túl kell maradnia, használhat egy öt percenként futó emlékeztetőt, amelynek célja egy olyan szemcse felébresztése, amely újraindít egy helyi időzítőt, amely az inaktiválás miatt elveszett lehet.

POCO-gabonaregisztrációk

Ha időzítőt vagy emlékeztetőt szeretne regisztrálni egy POCO-szemcsével, implementálja az IGrainBase interfészt, és injektálja a ITimerRegistry szemcse konstruktorába vagy IReminderRegistry annak konstruktorába.

using Orleans.Runtime;
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.RegisterTimer(
            grainContext,
            asyncCallback: static async state =>
            {
                // Omitted for brevity...
                // Use state

                await Task.CompletedTask;
            },
            state: this,
            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);
        }
    }
}

A fenti kód a következőket végzi el:

  • Meghatároz egy POCO-szemcsét, amely implementálja IGrainBaseaz , IPingGrainés IDisposable.
  • Regisztrál egy 10 másodpercenként meghívott időzítőt, és 3 másodperccel a regisztráció után indul el.
  • Amikor Ping meghívják, egy óránként meghívott emlékeztetőt regisztrál, és a regisztrációt követően azonnal elindul.
  • A Dispose metódus törli az emlékeztetőt, ha regisztrálva van.