Sdílet prostřednictvím


Časovače a připomenutí objektu Actor

Aktéři si můžou naplánovat pravidelnou práci tím, že si zaregistrují časovače nebo připomenutí. Tento článek ukazuje, jak používat časovače a připomenutí a vysvětluje rozdíly mezi nimi.

Časovače objektu actor

Časovače objektu actor poskytují jednoduchou obálku kolem časovače .NET nebo Java, aby metody zpětného volání respektovaly záruky souběžnosti založené na turnu, které poskytuje modul runtime Actors.

Aktéři můžou použít RegisterTimermetody (C#) nebo registerTimer(Java) a UnregisterTimer(C#) nebo unregisterTimer(Java) v základní třídě k registraci a zrušení registrace časovačů. Následující příklad ukazuje použití rozhraní API časovače. Rozhraní API jsou velmi podobná časovači .NET nebo časovači Java. V tomto příkladu při splnění časovače modul runtime Actors zavolá metodu MoveObject(C#) nebo moveObject(Java). Metoda zaručuje dodržování souběžnosti na základě. To znamená, že nebudou probíhat žádné jiné metody objektu actor ani časovač nebo zpětná volání připomenutí, dokud tento zpětný hovor nedokončí provádění.

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

Další období časovače se spustí po dokončení provádění zpětného volání. To znamená, že časovač se zastaví, když se zpětné volání spouští a spustí se po dokončení zpětného volání.

Modul runtime Actors ukládá změny provedené správcem stavu objektu actor po dokončení zpětného volání. Pokud dojde k chybě při ukládání stavu, objekt actor bude deaktivován a bude aktivována nová instance.

Na rozdíl od připomenutí nelze časovače aktualizovat. Pokud RegisterTimer se znovu zavolá, zaregistruje se nový časovač.

Všechny časovače se zastaví, když je objekt actor deaktivován jako součást uvolňování paměti. Po tom nejsou vyvolány žádné zpětná volání časovače. Modul runtime Actors také nezachovává žádné informace o časovači, které byly spuštěny před deaktivací. Je na objektu actor, aby zaregistroval všechny časovače, které potřebuje, když se v budoucnu znovu aktivuje. Další informace najdete v části o uvolňování paměti objektu actor.

Připomenutí objektu actor

Připomenutí jsou mechanismus pro aktivaci trvalých zpětných volání na objektu actor v určených časech. Jejich funkce jsou podobné časovačům. Na rozdíl od časovačů se ale připomenutí aktivují za všech okolností, dokud objekt actor explicitně neodregistruje nebo se objekt actor explicitně neodstraní. Konkrétně se připomenutí aktivují napříč deaktivací objektu actor a převzetím služeb při selhání, protože modul runtime Actors zachovává informace o připomenutích objektu actor pomocí zprostředkovatele stavu objektu actor. Na rozdíl od časovačů je možné existující připomenutí aktualizovat opětovným voláním metody registrace (RegisterReminderAsync) pomocí stejného reminderName.

Poznámka:

Spolehlivost připomenutí je vázána na záruky spolehlivosti stavu poskytované poskytovatelem stavu objektu actor. To znamená, že pro aktéry, jejichž stálost stavu je nastavena na Žádné, připomenutí se po převzetí služeb při selhání neaktivují.

Pokud chcete zaregistrovat připomenutí, objekt actor volá metodu RegisterReminderAsync uvedenou v základní třídě, jak je znázorněno v následujícím příkladu:

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
}

V tomto příkladu "Pay cell phone bill" je název připomenutí. Jedná se o řetězec, který objekt actor používá k jednoznačné identifikaci připomenutí. BitConverter.GetBytes(amountInDollars)(C#) je kontext přidružený k připomenutí. Předá se zpět objektu actor jako argument zpětnému volání připomenutí, tj. IRemindable.ReceiveReminderAsync(C#) nebo Remindable.receiveReminderAsync(Java).

Aktéři, kteří používají připomenutí, musí implementovat IRemindable rozhraní, jak je znázorněno v následujícím příkladu.

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

Když se aktivuje připomenutí, modul runtime Reliable Actors vyvolá metodu ReceiveReminderAsync(C#) nebo receiveReminderAsync(Java) na objektu Actor. Objekt actor může zaregistrovat více připomenutí a ReceiveReminderAsyncpři aktivaci některého z těchto připomenutí se vyvolá metoda (C#) nebo receiveReminderAsync(Java). Objekt actor může použít název připomenutí, který se předá ReceiveReminderAsyncmetodě (C#) nebo receiveReminderAsync(Java), aby zjistil, které připomenutí se aktivovalo.

Modul runtime Actors uloží stav objektu actor při ReceiveReminderAsyncdokončení volání (C#) nebo receiveReminderAsync(Java). Pokud dojde k chybě při ukládání stavu, objekt actor bude deaktivován a bude aktivována nová instance.

Pokud chcete zrušit registraci připomenutí, objekt actor volá metodu UnregisterReminderAsync(C#) nebo unregisterReminderAsync(Java), jak je znázorněno v následujících příkladech.

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

Jak je znázorněno výše, UnregisterReminderAsyncmetoda (C#) nebo unregisterReminderAsync(Java) přijímá IActorReminderrozhraní (C#) nebo ActorReminder(Java). Základní třída objektu actor podporuje metodu GetReminder(C#) nebo getReminder(Java), kterou lze použít k načtení IActorReminderrozhraní (C#) nebo ActorReminder(Java) předáním názvu připomenutí. To je praktické, protože objekt actor nemusí uchovávat IActorReminderrozhraní (C#) nebo ActorReminder(Java), které bylo vráceno z RegisterRemindervolání metody (C#) nebo registerReminder(Java).

Další kroky

Seznamte se s událostmi Reliable Actor a opětovnou relací: