Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il Orleans runtime fornisce due meccanismi, timer e promemoria, che consentono di specificare il comportamento periodico per i grani.
Timer
Usare i timer per creare un comportamento periodico dei grani che non è necessario per coprire più attivazioni (istanze del grano). Un timer è identico alla classe .NET System.Threading.Timer standard. Inoltre, i timer sono soggetti a garanzie di esecuzione su un singolo thread all'interno della grain activation su cui operano.
A ogni attivazione possono essere associati zero o più timer. Il runtime esegue ogni routine timer all'interno del contesto di runtime dell'attivazione associata.
Utilizzo del timer
Per avviare un timer, utilizzare il RegisterGrainTimer
metodo , che restituisce un IGrainTimer riferimento:
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
Per annullare il timer, eliminarlo.
Un timer smette di attivarsi se il grano viene disattivato o quando si verifica un errore e il silo si blocca.
Considerazioni importanti:
- Quando la raccolta di attivazione è abilitata, l'esecuzione di un callback timer non modifica lo stato dell'attivazione da inattivo a in uso. Ciò significa che non è possibile usare un timer per posticipare la disattivazione di attivazioni altrimenti inattive.
- Il periodo passato a
Grain.RegisterGrainTimer
è la quantità di tempo che passa dal momento in cui ilTask
restituito dacallback
si risolve al momento in cui dovrebbe verificarsi la prossima chiamata dicallback
. Ciò non solo impedisce la sovrapposizione delle chiamate successive acallback
, ma anche il tempocallback
necessario per completare influisce sulla frequenza in cuicallback
viene richiamato. Si tratta di una deviazione importante dalla semantica di System.Threading.Timer. - Ogni chiamata di
callback
viene recapitata a un'attivazione in un turno separato e non viene mai eseguita contemporaneamente ad altri turni sulla stessa attivazione. - Per impostazione predefinita, i callback non vengono intrecciati. È possibile abilitare l'interleaving impostando
Interleave
atrue
suGrainTimerCreationOptions
. - È possibile aggiornare i timer dei grani utilizzando il metodo
Change(TimeSpan, TimeSpan)
sull'istanza restituitaIGrainTimer
. - I callback possono mantenere attivo il grain, impedendo la raccolta se il periodo del timer è relativamente breve. Attiva questa funzione impostando
KeepAlive
sutrue
inGrainTimerCreationOptions
. - I callback possono ricevere un
CancellationToken
che viene annullato quando il timer viene eliminato o il grain inizia a disattivarsi. - I callback possono eliminare il timer granulare che li ha generati.
- I callback sono soggetti a filtri di chiamata granulari.
- I callback sono visibili nella traccia distribuita quando è abilitata la traccia distribuita.
- I grani POCO (classi di granularità che non ereditano da
Grain
) possono registrare timer di granularità usando ilRegisterGrainTimer
metodo di estensione.
Promemoria
I promemoria sono simili ai timer, con alcune differenze importanti:
- I promemoria sono persistenti e continuano a essere attivati in quasi tutte le situazioni (inclusi i riavvii parziali o completi del cluster) a meno che non vengano annullati in modo esplicito.
- Il promemoria "definizioni" viene scritto nello spazio di archiviazione. Tuttavia, ogni occorrenza specifica con il tempo specifico non viene archiviata. Questo ha l'effetto collaterale che se il cluster è inattivo quando è dovuta una specifica scadenza del promemoria, questa verrà ignorata e si attiverà solo alla scadenza successiva del promemoria.
- I promemoria sono associati a una granularità, non a un'attivazione specifica.
- Se a un grano non è associata alcuna attivazione quando un promemoria scatta, Orleans crea l'attivazione del grano. Se un'attivazione diventa inattiva e viene disattivata, un promemoria associato allo stesso "grain" riattiva il "grain" quando viene attivato successivamente.
- Il recapito dei promemoria avviene tramite messaggio ed è soggetto alla stessa semantica di interleaving di tutti gli altri metodi granulari.
- Non dovresti usare promemoria per timer ad alta frequenza; il periodo deve essere misurato in minuti, ore o giorni.
Configurazione
Poiché i promemoria sono persistenti, si basano sull'archiviazione per funzionare. È necessario specificare quale risorsa di archiviazione usare prima che il sottosistema di promemoria possa funzionare. Configura uno dei provider di promemoria utilizzando i metodi di estensione Use{X}ReminderService
, dove X
è il nome del provider, ad esempio UseAzureTableReminderService.
Configurazione tabella di 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();
Se si desidera solo un'implementazione segnaposto dei promemoria che funzioni senza dover configurare un account Azure o un database SQL, questo fornisce un'implementazione solo per sviluppo del sistema di promemoria.
var silo = new HostBuilder()
.UseOrleans(builder =>
{
builder.UseInMemoryReminderService();
})
.Build();
Importante
Se si dispone di un cluster eterogeneo, in cui i silo gestiscono tipi di granularità diversi (implementano interfacce diverse), ogni silo deve aggiungere la configurazione per i promemoria, anche se il silo stesso non gestisce alcun promemoria.
Utilizzo dei promemoria
Un grain che utilizza promemoria deve implementare il metodo IRemindable.ReceiveReminder.
Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
Console.WriteLine("Thanks for reminding me-- I almost forgot!");
return Task.CompletedTask;
}
Per avviare un promemoria, utilizzare il Grain.RegisterOrUpdateReminder metodo , che restituisce un IGrainReminder oggetto :
protected Task<IGrainReminder> RegisterOrUpdateReminder(
string reminderName,
TimeSpan dueTime,
TimeSpan period)
-
reminderName
: è una stringa che deve identificare in modo univoco il promemoria nell'ambito contestuale. -
dueTime
: specifica una quantità di tempo di attesa prima di emettere il primo tick del timer. -
period
: specifica il periodo del timer.
Poiché i promemoria sopravvivono alla durata di qualsiasi singola attivazione, è necessario annullarli in modo esplicito (anziché eliminarli). Annullare un promemoria chiamando Grain.UnregisterReminder:
protected Task UnregisterReminder(IGrainReminder reminder)
reminder
è l'oggetto handle restituito da Grain.RegisterOrUpdateReminder.
Le istanze di IGrainReminder
non sono sicuramente valide oltre la durata di un'attivazione. Se vuoi identificare un promemoria in modo permanente, usa una stringa contenente il nome del promemoria.
Se si dispone solo del nome del promemoria e si necessita dell'istanza corrispondente, chiamare il metodo IGrainReminder
: Grain.GetReminder
protected Task<IGrainReminder> GetReminder(string reminderName)
Decidere quale usare
È consigliabile usare i timer nelle circostanze seguenti:
- Se non importa (o è auspicabile) che il timer smetta di funzionare quando l'attivazione si disattiva o si verificano malfunzionamenti.
- La risoluzione del timer è piccola (ad esempio, ragionevolmente espressa in secondi o minuti).
- È possibile avviare il callback timer da Grain.OnActivateAsync() o quando viene invocato un metodo grain.
È consigliabile usare i promemoria nelle circostanze seguenti:
- Quando il comportamento periodico deve sopravvivere all'attivazione e a eventuali errori.
- Esecuzione di attività poco frequenti (ad esempio, che si possono esprimere ragionevolmente in minuti, ore o giorni).
Combinare timer e promemoria
È possibile prendere in considerazione l'uso di una combinazione di promemoria e timer per raggiungere l'obiettivo. Ad esempio, se è necessario un timer con una piccola risoluzione che deve sopravvivere tra le attivazioni, è possibile usare un promemoria in esecuzione ogni cinque minuti. Il suo scopo sarebbe quello di risvegliare un grano che riattiva un timer locale possibilmente perso a causa di disattivazione.
Registrazioni dei grain POCO
Per registrare un timer o un promemoria con un grain POCO, implementare l'interfaccia IGrainBase e iniettare ITimerRegistry o IReminderRegistry nel costruttore del grain.
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);
}
}
}
Il codice precedente esegue le operazioni seguenti:
- Definisce un granulare POCO che implementa IGrainBase,
IPingGrain
e IDisposable. - Registra un timer richiamato ogni 10 secondi, a partire da 3 secondi dopo la registrazione.
- Quando
Ping
viene chiamato, registra un promemoria richiamato ogni ora, a partire immediatamente dopo la registrazione. - Il
Dispose
metodo annulla il promemoria se è registrato.