0

Microsoft Orleans #03: Timers y Reminders

En esta clase aprenderemos cómo utilizar Timers y Reminders en Orleans para programar tareas automáticas dentro de los Granos.

Objetivos de la Clase

  • Comprender la diferencia entre Timers y Reminders en Orleans.
  • Implementar Timers para ejecutar tareas recurrentes mientras un Grano está activo.
  • Implementar Reminders para tareas periódicas que deben ejecutarse incluso si el Grano está inactivo.
  • Probar el funcionamiento de ambos mecanismos.

Diferencia entre Timers y Reminders

Tanto los Timers como los Reminders permiten la ejecución de tareas en intervalos de tiempo específicos, pero tienen diferencias clave:

CaracterísticaTimersReminders
Se ejecuta mientras el Grano está activo✅ Sí❌ No siempre
Persiste después de reiniciar el Silo❌ No✅ Sí
Necesita ser reiniciado manualmente✅ Sí❌ No
Ejemplo de usoActualización en tiempo realRecordatorio de pago mensual

Implementar un Timer en Orleans

Los Timers en Orleans permiten ejecutar una tarea de forma repetitiva mientras el Grano esté activo.

1. Definir la interfaz del Grano

Crea ITimerGrain.cs en la carpeta Granos:

using System.Threading.Tasks;
using Orleans;

public interface ITimerGrain : IGrainWithGuidKey
{
    Task StartTimer();
    Task StopTimer();
}

2. Implementar el Grano con un Timer

Crea TimerGrain.cs en la carpeta Granos:

using System;
using System.Threading.Tasks;
using Orleans;

public class TimerGrain : Grain, ITimerGrain
{
    private IDisposable _timer;

    public Task StartTimer()
    {
        _timer = RegisterTimer(
            async (state) =>
            {
                Console.WriteLine($"[{DateTime.UtcNow}] Ejecutando tarea del Timer...");
                await Task.CompletedTask;
            },
            state: null,
            dueTime: TimeSpan.FromSeconds(1),
            period: TimeSpan.FromSeconds(5) // Se ejecuta cada 5 segundos
        );

        return Task.CompletedTask;
    }

    public Task StopTimer()
    {
        _timer?.Dispose();
        _timer = null;
        return Task.CompletedTask;
    }
}

Explicación del código

  • RegisterTimer(...) crea un Timer que ejecuta la tarea cada 5 segundos.
  • Dispose() detiene el Timer.
  • Si el Grano se desactiva, el Timer se detiene automáticamente.

Implementar un Reminder en Orleans

Los Reminders permiten programar tareas periódicas incluso si el Grano está inactivo.

1. Definir la interfaz del Grano

Crea IReminderGrain.cs en Granos:

using System.Threading.Tasks;
using Orleans;

public interface IReminderGrain : IGrainWithGuidKey
{
    Task RegisterReminder();
    Task ReceiveReminder(string reminderName, TickStatus status);
}

2. Implementar el Grano con un Reminder

Crea ReminderGrain.cs en Granos:

using System;
using System.Threading.Tasks;
using Orleans;
using Orleans.Runtime;

public class ReminderGrain : Grain, IReminderGrain, IRemindable
{
    public async Task RegisterReminder()
    {
        await RegisterOrUpdateReminder(
            reminderName: "RecordatorioDiario",
            dueTime: TimeSpan.FromSeconds(10), // Primera ejecución en 10 segundos
            period: TimeSpan.FromSeconds(20) // Se repite cada 20 segundos
        );
    }

    public Task ReceiveReminder(string reminderName, TickStatus status)
    {
        Console.WriteLine($"[{DateTime.UtcNow}] Reminder activado: {reminderName}");
        return Task.CompletedTask;
    }
}

Explicación del código

  • RegisterOrUpdateReminder(...) registra un Reminder que se ejecuta cada 20 segundos.
  • ReceiveReminder(...) se ejecuta cada vez que Orleans activa el Reminder.
  • Incluso si el Grano está inactivo, Orleans recordará ejecutarlo cuando sea necesario.

Configurar Orleans para habilitar Reminders

Para que Orleans pueda manejar Reminders, debemos habilitar el servicio de Reminders en el Silo.

Edita Program.cs en OrleansDemo y agrégale lo siguiente:

builder.UseInMemoryReminderService();

El código completo de Program.cs quedará así:

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Orleans;
using Orleans.Hosting;

class Program
{
    static async Task Main(string[] args)
    {
        var host = Host.CreateDefaultBuilder()
            .UseOrleans(builder =>
            {
                builder.UseLocalhostClustering();
                builder.UseInMemoryReminderService(); // Habilita Reminders
            })
            .Build();

        await host.RunAsync();
    }
}

Probar Timers y Reminders

1. Probar el Timer

Edita Program.cs en OrleansClient y agrega el siguiente código para probar el Timer:

using System;
using System.Threading.Tasks;
using Orleans;
using Orleans.Hosting;

class Program
{
    static async Task Main(string[] args)
    {
        var client = new ClientBuilder()
            .UseLocalhostClustering()
            .Build();

        await client.Connect();
        Console.WriteLine("Cliente conectado a Orleans.");

        var timerGrain = client.GetGrain<ITimerGrain>(Guid.NewGuid());
        await timerGrain.StartTimer();
        
        Console.WriteLine("Timer iniciado. Presiona Enter para detener.");
        Console.ReadLine();

        await timerGrain.StopTimer();
        Console.WriteLine("Timer detenido.");
    }
}

Salida esperada en consola:

Cliente conectado a Orleans.
Timer iniciado. Presiona Enter para detener.
[2024-02-05 12:00:00] Ejecutando tarea del Timer...
[2024-02-05 12:00:05] Ejecutando tarea del Timer...
[2024-02-05 12:00:10] Ejecutando tarea del Timer...

2. Probar el Reminder

Modifica Program.cs en OrleansClient para probar los Reminders:

var reminderGrain = client.GetGrain<IReminderGrain>(Guid.NewGuid());
await reminderGrain.RegisterReminder();
Console.WriteLine("Reminder registrado. Presiona Enter para salir.");
Console.ReadLine();

Salida esperada en consola:

Cliente conectado a Orleans.
Reminder registrado. Presiona Enter para salir.
[2024-02-05 12:00:10] Reminder activado: RecordatorioDiario
[2024-02-05 12:00:30] Reminder activado: RecordatorioDiario

Cuestionario de Autoevaluación

  1. ¿Cuál es la diferencia principal entre un Timer y un Reminder en Orleans?
  2. ¿Qué sucede con un Timer cuando el Grano se desactiva?
  3. ¿Cómo Orleans recuerda ejecutar un Reminder después de un reinicio?
  4. ¿Qué método se usa para registrar un Timer?
  5. ¿Cómo se configura el servicio de Reminders en el Silo?

Resumen de la Clase

  • Los Timers permiten ejecutar tareas repetitivas solo cuando el Grano está activo.
  • Los Reminders ejecutan tareas periódicas incluso si el Grano está inactivo o el Silo se reinicia.
  • Los Timers se detienen automáticamente cuando el Grano se desactiva.
  • Los Reminders deben registrarse y Orleans se encarga de ejecutarlos según su programación.
  • Probamos ambos mecanismos en Orleans y confirmamos su funcionamiento.

Próxima Clase: Comunicación entre Granos

En la siguiente clase, aprenderemos cómo los Granos pueden llamarse entre sí para compartir datos y coordinar tareas.

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *