Delen via


Timers en herinneringen voor actor

Actoren kunnen periodiek werk op zichzelf plannen door timers of herinneringen te registreren. In dit artikel wordt beschreven hoe u timers en herinneringen gebruikt en de verschillen tussen deze timers en herinneringen uitlegt.

Actortimers

Actortimers bieden een eenvoudige wrapper rond een .NET- of Java-timer om ervoor te zorgen dat de callback-methoden de op turn gebaseerde gelijktijdigheidsgaranties respecteren die de Actors-runtime biedt.

Actoren kunnen de RegisterTimermethoden (C#) of registerTimer(Java) en UnregisterTimer(C#) of unregisterTimer(Java) op hun basisklasse gebruiken om hun timers te registreren en de registratie ervan ongedaan te maken. In het onderstaande voorbeeld ziet u het gebruik van timer-API's. De API's zijn vergelijkbaar met de .NET-timer of Java-timer. In dit voorbeeld roept MoveObjectde Actors-runtime de methode (C#) of moveObject(Java) aan wanneer de timer moet worden voltooid. De methode wordt gegarandeerd om de gelijktijdigheid op basis van turn-based te respecteren. Dit betekent dat er geen andere actormethoden of timer/herinnering callbacks worden uitgevoerd totdat deze callback is voltooid.

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;});
        });
    }
}

De volgende periode van de timer wordt gestart nadat de callback is voltooid. Dit houdt in dat de timer wordt gestopt terwijl de callback wordt uitgevoerd en wordt gestart wanneer de callback is voltooid.

De Actors-runtime slaat wijzigingen op die zijn aangebracht in state manager van de actor wanneer de callback is voltooid. Als er een fout optreedt bij het opslaan van de status, wordt dat actorobject gedeactiveerd en wordt een nieuw exemplaar geactiveerd.

In tegenstelling tot herinneringen kunnen timers niet worden bijgewerkt. Als RegisterTimer deze opnieuw wordt aangeroepen, wordt er een nieuwe timer geregistreerd.

Alle timers worden gestopt wanneer de actor wordt gedeactiveerd als onderdeel van garbagecollection. Daarna worden geen timer-callbacks aangeroepen. De Actors-runtime behoudt ook geen informatie over de timers die vóór deactivering werden uitgevoerd. Het is aan de actor om timers te registreren die nodig zijn wanneer deze in de toekomst opnieuw wordt geactiveerd. Zie de sectie over actor garbagecollection voor meer informatie.

Actorherinneringen

Herinneringen zijn een mechanisme voor het activeren van permanente callbacks op een actor op opgegeven tijdstippen. Hun functionaliteit is vergelijkbaar met timers. In tegenstelling tot timers worden herinneringen onder alle omstandigheden geactiveerd totdat de actor de registratie ervan expliciet ongedaan maakt of de actor expliciet wordt verwijderd. Met name worden herinneringen geactiveerd voor actordeactivaties en failovers, omdat de Actors-runtime informatie over de herinneringen van de actor persistent maakt met behulp van de actorstatusprovider. In tegenstelling tot timers kunnen bestaande herinneringen worden bijgewerkt door de registratiemethode (RegisterReminderAsync) opnieuw aan te roepen met dezelfde reminderName.

Notitie

De betrouwbaarheid van herinneringen is gekoppeld aan de statusbetrouwbaarheidsgaranties van de provider van de actorstatus. Dit betekent dat voor actoren waarvan de statuspersistentie is ingesteld op Geen, de herinneringen niet worden geactiveerd na een failover.

Als u een herinnering wilt registreren, roept een actor de RegisterReminderAsync methode aan die is opgegeven in de basisklasse, zoals wordt weergegeven in het volgende voorbeeld:

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
}

In dit voorbeeld "Pay cell phone bill" is dit de naam van de herinnering. Dit is een tekenreeks die de actor gebruikt om een herinnering uniek te identificeren. BitConverter.GetBytes(amountInDollars)(C#) is de context die is gekoppeld aan de herinnering. Deze wordt als argument doorgegeven aan de actor als argument voor de callback van de herinnering, bijvoorbeeld IRemindable.ReceiveReminderAsync(C#) of Remindable.receiveReminderAsync(Java).

Actoren die herinneringen gebruiken, moeten de IRemindable interface implementeren, zoals wordt weergegeven in het onderstaande voorbeeld.

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);
    }

Wanneer een herinnering wordt geactiveerd, roept de Reliable Actors-runtime de ReceiveReminderAsyncmethode (C#) of receiveReminderAsync(Java) op de Actor aan. Een actor kan meerdere herinneringen registreren en de ReceiveReminderAsyncmethode (C#) of receiveReminderAsync(Java) wordt aangeroepen wanneer een van deze herinneringen wordt geactiveerd. De actor kan de naam van de herinnering gebruiken die wordt doorgegeven aan de ReceiveReminderAsyncmethode (C#) of receiveReminderAsync(Java) om te achterhalen welke herinnering is geactiveerd.

De Actors-runtime slaat de status van de actor op wanneer de ReceiveReminderAsyncaanroep (C#) of receiveReminderAsync(Java) is voltooid. Als er een fout optreedt bij het opslaan van de status, wordt dat actorobject gedeactiveerd en wordt een nieuw exemplaar geactiveerd.

Als u de registratie van een herinnering ongedaan wilt maken, roept een actor de UnregisterReminderAsyncmethode (C#) of unregisterReminderAsync(Java) aan, zoals wordt weergegeven in de onderstaande voorbeelden.

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

Zoals hierboven wordt weergegeven, accepteert de UnregisterReminderAsyncmethode (C#) of unregisterReminderAsync(Java) een IActorReminderinterface (C#) of ActorReminder(Java). De actorbasisklasse ondersteunt een GetRemindermethode (C#) of getReminder(Java) die kan worden gebruikt om de IActorReminderinterface (C#) of ActorReminder(Java) op te halen door de naam van de herinnering door te geven. Dit is handig omdat de actor de IActorReminderinterface (C#) of ActorReminder(Java) die is geretourneerd vanuit de aanroep van de RegisterRemindermethode (C#) of registerReminder(Java) niet hoeft te behouden.

Volgende stappen

Meer informatie over Reliable Actor-gebeurtenissen en -reentrancy: