Aktörstimers och påminnelser

Aktörer kan schemalägga periodiskt arbete på sig själva genom att registrera timers eller påminnelser. Den här artikeln visar hur du använder timers och påminnelser och förklarar skillnaderna mellan dem.

Aktörstimers

Aktörstimers tillhandahåller en enkel omslutning runt en .NET- eller Java-timer för att säkerställa att motringningsmetoderna respekterar de turbaserade samtidighetsgarantierna som Actors-körningen tillhandahåller.

Aktörer kan använda RegisterTimermetoderna (C#) eller registerTimer(Java) och UnregisterTimer(C#) eller unregisterTimer(Java) i sin basklass för att registrera och avregistrera sina timers. Exemplet nedan visar användningen av timer-API:er. API:erna liknar .NET-timern eller Java-timern. I det här exemplet anropar Actors runtime MoveObjectmetoden (C#) eller moveObject(Java) när timern förfaller. Metoden är garanterad att respektera den turbaserade samtidigheten. Det innebär att inga andra aktörsmetoder eller timer-/påminnelseåteranrop pågår förrän återanropet har slutfört körningen.

class VisualObjectActor : Actor, IVisualObject
{
    private IActorTimer _updateTimer;

    public VisualObjectActor(ActorService actorService, ActorId actorId)
        : base(actorService, actorId)
    {
    }

    protected override Task OnActivateAsync()
    {
        ...

        _updateTimer = RegisterTimer(
            MoveObject,                     // Callback method
            null,                           // Parameter to pass to the callback method
            TimeSpan.FromMilliseconds(15),  // Amount of time to delay before the callback is invoked
            TimeSpan.FromMilliseconds(15)); // Time interval between invocations of the callback method

        return base.OnActivateAsync();
    }

    protected override Task OnDeactivateAsync()
    {
        if (_updateTimer != null)
        {
            UnregisterTimer(_updateTimer);
        }

        return base.OnDeactivateAsync();
    }

    private Task MoveObject(object state)
    {
        ...
        return Task.FromResult(true);
    }
}
public class VisualObjectActorImpl extends FabricActor implements VisualObjectActor
{
    private ActorTimer updateTimer;

    public VisualObjectActorImpl(FabricActorService actorService, ActorId actorId)
    {
        super(actorService, actorId);
    }

    @Override
    protected CompletableFuture onActivateAsync()
    {
        ...

        return this.stateManager()
                .getOrAddStateAsync(
                        stateName,
                        VisualObject.createRandom(
                                this.getId().toString(),
                                new Random(this.getId().toString().hashCode())))
                .thenApply((r) -> {
                    this.registerTimer(
                            (o) -> this.moveObject(o),                        // Callback method
                            "moveObject",
                            null,                                             // Parameter to pass to the callback method
                            Duration.ofMillis(10),                            // Amount of time to delay before the callback is invoked
                            Duration.ofMillis(timerIntervalInMilliSeconds));  // Time interval between invocations of the callback method
                    return null;
                });
    }

    @Override
    protected CompletableFuture onDeactivateAsync()
    {
        if (updateTimer != null)
        {
            unregisterTimer(updateTimer);
        }

        return super.onDeactivateAsync();
    }

    private CompletableFuture moveObject(Object state)
    {
        ...
        return this.stateManager().getStateAsync(this.stateName).thenCompose(v -> {
            VisualObject v1 = (VisualObject)v;
            v1.move();
            return (CompletableFuture<?>)this.stateManager().setStateAsync(stateName, v1).
                    thenApply(r -> {
                      ...
                      return null;});
        });
    }
}

Nästa period av timern startar när återanropet har slutfört körningen. Detta innebär att timern stoppas medan återanropet körs och startas när återanropet är klart.

Actors-körningen sparar ändringar som gjorts i aktörens state manager när återanropet är klart. Om ett fel uppstår när tillståndet sparas inaktiveras aktörsobjektet och en ny instans aktiveras.

Till skillnad från påminnelser kan timers inte uppdateras. Om RegisterTimer anropas igen registreras en ny timer.

Alla timers stoppas när aktören inaktiveras som en del av skräpinsamlingen. Inga timer-motringningar anropas efter det. Actors-körningen behåller heller ingen information om de timers som kördes före inaktivering. Det är upp till aktören att registrera alla timers som behövs när den återaktiveras i framtiden. Mer information finns i avsnittet om aktörens skräpinsamling.

Aktörspåminnelser

Påminnelser är en mekanism för att utlösa beständiga återanrop på en aktör vid angivna tidpunkter. Deras funktioner liknar timers. Men till skillnad från timers utlöses påminnelser under alla omständigheter tills aktören uttryckligen avregistrerar dem eller aktören uttryckligen tas bort. Mer specifikt utlöses påminnelser mellan aktörsaktiveringar och redundans eftersom Actors-körningen bevarar information om aktörens påminnelser med hjälp av aktörens tillståndsprovider. Till skillnad från timers kan befintliga påminnelser uppdateras genom att anropa registreringsmetoden (RegisterReminderAsync) igen med samma reminderName.

Kommentar

Tillförlitligheten för påminnelser är kopplad till de tillståndstillförlitlighetsgarantier som tillhandahålls av aktörens tillståndsprovider. Det innebär att för aktörer vars tillståndsbeständighet är inställt på Ingen utlöses inte påminnelserna efter en redundansväxling.

För att registrera en påminnelse anropar en aktör metoden RegisterReminderAsync som tillhandahålls i basklassen, enligt följande exempel:

protected override async Task OnActivateAsync()
{
    string reminderName = "Pay cell phone bill";
    int amountInDollars = 100;

    IActorReminder reminderRegistration = await this.RegisterReminderAsync(
        reminderName,
        BitConverter.GetBytes(amountInDollars),
        TimeSpan.FromDays(3),    //The amount of time to delay before firing the reminder
        TimeSpan.FromDays(1));    //The time interval between firing of reminders
}
@Override
protected CompletableFuture onActivateAsync()
{
    String reminderName = "Pay cell phone bill";
    int amountInDollars = 100;

    ActorReminder reminderRegistration = this.registerReminderAsync(
            reminderName,
            state,
            dueTime,    //The amount of time to delay before firing the reminder
            period);    //The time interval between firing of reminders
}

I det här exemplet "Pay cell phone bill" är påminnelsenamnet. Det här är en sträng som aktören använder för att unikt identifiera en påminnelse. BitConverter.GetBytes(amountInDollars)(C#) är den kontext som är associerad med påminnelsen. Den skickas tillbaka till aktören som ett argument till återanropet till påminnelsen, d.v.s. IRemindable.ReceiveReminderAsync(C#) eller Remindable.receiveReminderAsync(Java).

Aktörer som använder påminnelser måste implementera IRemindable gränssnittet, enligt exemplet nedan.

public class ToDoListActor : Actor, IToDoListActor, IRemindable
{
    public ToDoListActor(ActorService actorService, ActorId actorId)
        : base(actorService, actorId)
    {
    }

    public Task ReceiveReminderAsync(string reminderName, byte[] context, TimeSpan dueTime, TimeSpan period)
    {
        if (reminderName.Equals("Pay cell phone bill"))
        {
            int amountToPay = BitConverter.ToInt32(context, 0);
            System.Console.WriteLine("Please pay your cell phone bill of ${0}!", amountToPay);
        }
        return Task.FromResult(true);
    }
}
public class ToDoListActorImpl extends FabricActor implements ToDoListActor, Remindable
{
    public ToDoListActor(FabricActorService actorService, ActorId actorId)
    {
        super(actorService, actorId);
    }

    public CompletableFuture receiveReminderAsync(String reminderName, byte[] context, Duration dueTime, Duration period)
    {
        if (reminderName.equals("Pay cell phone bill"))
        {
            int amountToPay = ByteBuffer.wrap(context).getInt();
            System.out.println("Please pay your cell phone bill of " + amountToPay);
        }
        return CompletableFuture.completedFuture(true);
    }

När en påminnelse utlöses anropar Reliable Actors-körningen ReceiveReminderAsyncmetoden (C#) eller receiveReminderAsync(Java) på aktören. En aktör kan registrera flera påminnelser och ReceiveReminderAsyncmetoden (C#) eller receiveReminderAsync(Java) anropas när någon av dessa påminnelser utlöses. Aktören kan använda påminnelsenamnet som skickas till ReceiveReminderAsyncmetoden (C#) eller receiveReminderAsync(Java) för att ta reda på vilken påminnelse som utlöstes.

Actors-körningen sparar aktörens tillstånd när (C#) eller receiveReminderAsync(Java)-anropet ReceiveReminderAsyncär klart. Om ett fel uppstår när tillståndet sparas inaktiveras aktörsobjektet och en ny instans aktiveras.

Om du vill avregistrera en påminnelse anropar UnregisterReminderAsyncen aktör metoden (C#) eller unregisterReminderAsync(Java), enligt exemplen nedan.

IActorReminder reminder = GetReminder("Pay cell phone bill");
Task reminderUnregistration = await UnregisterReminderAsync(reminder);
ActorReminder reminder = getReminder("Pay cell phone bill");
CompletableFuture reminderUnregistration = unregisterReminderAsync(reminder);

Som du ser ovan UnregisterReminderAsyncaccepterar metoden (C#) eller unregisterReminderAsync(Java) ett IActorReminder(C#) eller ActorReminder(Java)-gränssnitt. Aktörsbasklassen stöder en GetReminder(C#) eller getReminder(Java)-metod som kan användas för att hämta IActorRemindergränssnittet (C#) eller ActorReminder(Java) genom att skicka in påminnelsenamnet. Det här är praktiskt eftersom aktören inte behöver spara IActorRemindergränssnittet (C#) eller ActorReminder(Java) som returnerades från RegisterReminder(C#) eller registerReminder(Java)-metodanropet.

Nästa steg

Lär dig mer om reliable actor-händelser och återaktivering: