Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El Orleans tiempo de ejecución proporciona dos mecanismos, temporizadores y recordatorios, que permiten especificar el comportamiento periódico de los granos.
Temporizadores
Utiliza temporizadores para crear un comportamiento periódico del grano sin necesidad de abarcar varias activaciones (instancias del grano). Un temporizador es idéntico a la clase estándar .NET de System.Threading.Timer. Además, los temporizadores están sujetos a garantías de ejecución de un solo subproceso dentro de la activación específica en la que operan.
Cada activación puede tener cero o más temporizadores asociados. El tiempo de ejecución ejecuta cada rutina del temporizador en el contexto de ejecución de su activación asociada.
Uso del temporizador
Para iniciar un temporizador, use el método RegisterGrainTimer
, que devuelve una referencia IGrainTimer:
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
Para cancelar el temporizador, deshágalo.
Un temporizador deja de desencadenarse si el grano se desactiva o cuando se produce una falla y su silo colapsa.
Consideraciones importantes:
- Cuando la recopilación de activaciones está habilitada, ejecutar un callback del temporizador no cambia el estado de la activación de inactivo a en uso. Esto significa que no puede usar un temporizador para posponer la desactivación de activaciones que de otro modo estarían inactivas.
- El período pasado a
Grain.RegisterGrainTimer
es la cantidad de tiempo que pasa desde el momento en que elTask
devuelto porcallback
se resuelve hasta el momento en que debe producirse la siguiente invocación decallback
. Esto no solo impide que las llamadas sucesivas acallback
se superpongan, sino que también implica que la duración quecallback
tarda en completarse afecta a la frecuencia con la que se invoca acallback
. Se trata de una desviación importante de la semántica de System.Threading.Timer. - Cada invocación de
callback
se entrega a una activación en un turno independiente y nunca se ejecuta simultáneamente con otros turnos en la misma activación. - Las devoluciones de llamada no se intercalan de forma predeterminada. Puede habilitar la intercalación estableciendo
Interleave
atrue
enGrainTimerCreationOptions
. - Puede actualizar temporizadores de grano utilizando el método
Change(TimeSpan, TimeSpan)
en la instancia devueltaIGrainTimer
. - Los callbacks pueden mantener el componente activo, evitando que se recoja si el período del temporizador es relativamente corto. Active esto configurando
KeepAlive
atrue
enGrainTimerCreationOptions
. - Las funciones de retorno pueden recibir un
CancellationToken
que se cancela cuando se elimina el temporizador o el grano comienza a desactivarse. - Los callbacks pueden descartar el temporizador de granulación que los activó.
- Las devoluciones de llamada están sujetas a filtros de llamada de intervalo de agregación.
- Las devoluciones de llamada son visibles en el seguimiento distribuido cuando el seguimiento distribuido está habilitado.
- Los granos POCO (clases de grano que no heredan de
Grain
) pueden registrar temporizadores mediante el método de extensiónRegisterGrainTimer
.
Recordatorios
Los avisos son similares a los temporizadores, con algunas diferencias importantes:
- Los recordatorios son persistentes y continúan desencadenando en casi todas las situaciones (incluidos los reinicios parciales o completos del clúster), a menos que se cancele explícitamente.
- Los avisos "definiciones" se escriben en el almacenamiento. Sin embargo, cada aparición específica con su tiempo específico no se almacena. Esto tiene el efecto secundario de que si el clúster está inactivo cuando se debe un tic de recordatorio específico, se perderá y solo se producirá el siguiente tic del aviso.
- Los recordatorios están asociados a un grano, no a ninguna activación específica.
- Si un grano no tiene ninguna activación asociada cuando se marca un aviso, Orleans crea la activación de grano. Si una activación se vuelve inactiva y se desactiva, un recordatorio asociado al mismo grano reactiva el grano cuando se marca a continuación.
- La entrega del recordatorio se produce a través del mensaje y está sujeta a la misma semántica intercalada que todos los demás métodos de grano.
- No debe usar recordatorios para temporizadores de alta frecuencia; su período debe medirse en minutos, horas o días.
Configuración
Dado que los recordatorios son persistentes, dependen del almacenamiento para funcionar. Debe especificar la copia de seguridad de almacenamiento que se va a usar antes de que el subsistema de recordatorio pueda funcionar. Para ello, configure uno de los proveedores de recordatorios a través Use{X}ReminderService
de métodos de extensión, donde X
es el nombre del proveedor (por ejemplo, UseAzureTableReminderService).
Configuración de tabla de 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();
Si solo desea que una implementación de marcador de posición de recordatorios funcione sin necesidad de configurar una cuenta de Azure o una base de datos SQL, esto proporciona una implementación solo de desarrollo del sistema de recordatorios:
var silo = new HostBuilder()
.UseOrleans(builder =>
{
builder.UseInMemoryReminderService();
})
.Build();
Importante
Si tiene un clúster heterogéneo, donde los silos controlan diferentes tipos de intervalos de agregación (implementan interfaces diferentes), cada silo debe agregar la configuración de recordatorios, aunque el propio silo no controle ningún recordatorio.
Uso de recordatorios
Un grano que use recordatorios debe implementar el método IRemindable.ReceiveReminder.
Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
Console.WriteLine("Thanks for reminding me-- I almost forgot!");
return Task.CompletedTask;
}
Para iniciar un recordatorio, use el método Grain.RegisterOrUpdateReminder, que devuelve un objeto IGrainReminder:
protected Task<IGrainReminder> RegisterOrUpdateReminder(
string reminderName,
TimeSpan dueTime,
TimeSpan period)
-
reminderName
: es una cadena que debe identificar de forma única el aviso dentro del ámbito del grano contextual. -
dueTime
: especifica una cantidad de tiempo de espera antes de emitir el tic del primer temporizador. -
period
: especifica el período del temporizador.
Dado que los recordatorios sobreviven a la duración de cualquier activación única, debe cancelarlos explícitamente (en lugar de eliminarlos). Cancele un aviso llamando a Grain.UnregisterReminder:
protected Task UnregisterReminder(IGrainReminder reminder)
reminder
es el objeto manipulador devuelto por Grain.RegisterOrUpdateReminder.
No se garantiza que las instancias de IGrainReminder
sean válidas más allá de la duración de una activación. Si desea identificar un recordatorio de forma persistente, use una cadena que contenga el nombre del recordatorio.
Si solo tiene el nombre del recordatorio y necesita la instancia correspondiente IGrainReminder
, llame al método Grain.GetReminder.
protected Task<IGrainReminder> GetReminder(string reminderName)
Decida cuál utilizar
Se recomienda usar temporizadores en las siguientes circunstancias:
- Si no importa (o es deseable) que el temporizador deje de funcionar cuando la activación se desactive o ocurran fallos.
- La resolución del temporizador es pequeña (por ejemplo, razonablemente expresable en segundos o minutos).
- Puede iniciar la devolución de llamada del temporizador desde Grain.OnActivateAsync() o cuando se invoca un método de grano.
Se recomienda usar recordatorios en las siguientes circunstancias:
- Cuando el comportamiento periódico necesita sobrevivir a la activación y a los errores.
- Realizar tareas poco frecuentes (por ejemplo, razonablemente expresables en minutos, horas o días).
Combinar recordatorios y temporizadores
Es posible que considere la posibilidad de usar una combinación de recordatorios y temporizadores para lograr su objetivo. Por ejemplo, si necesita un temporizador con una resolución pequeña que debe sobrevivir entre activaciones, puede usar un recordatorio que se ejecute cada cinco minutos. Su propósito sería despertar un grano que reinicie un temporizador local posiblemente perdido debido a la desactivación.
Registros de grano POCO
Para registrar un temporizador o recordatorio con un grano POCO, implemente la IGrainBase interfaz e inserte ITimerRegistry o IReminderRegistry en el constructor del grano.
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);
}
}
}
El código anterior hace lo siguiente:
- Define un grano POCO que implementa IGrainBase,
IPingGrain
y IDisposable. - Registra un temporizador invocado cada 10 segundos, comenzando 3 segundos después del registro.
- Cuando se llama a
Ping
, registra un recordatorio que se invoca cada hora, comenzando inmediatamente después del registro. - El método
Dispose
cancela el aviso si está registrado.