Orleans运行时提供了两种机制,称为定时器和提醒器,使开发人员能够指定grain的周期性行为。
定时器用于创建不需要跨越多个激活(grain的实例化)的周期性的grain的行为。它基本上等同于标准的.NET System.Threading.Timer类。此外,在它运行的grain激活中,它还受单线程执行保证的约束。
每个激活都可以具有与其相关联的零个或多个计时器。在与定时器关联激活的运行时上下文中,运行时执行每个定时器的例程。
要启动定时器,请使用Grain.RegisterTimer方法,该方法返回 IDisposable引用:
public IDisposable RegisterTimer(
Func<object, Task> asyncCallback, // function invoked when the timer ticks
object state, // object tp pass to asyncCallback
TimeSpan dueTime, // time to wait before the first timer tick
TimeSpan period) // the period of the timer
通过disposing可以取消计时器。
如果激活被禁用,或者发生故障且其silo崩溃,则定时器将停止触发。
重要的考量因素
提醒与定时器类似,但有一些重要区别:
提醒器是持久化的,依赖于存储来发挥作用。您必须在提醒器的子系统运行之前,指定要使用的存储后备。这是通过扩展方法UseXReminderService
,来配置其中提醒器的提供程序之一而完成的,其中X是提供程序的名称,例如UseAzureTableReminderService
。
Azure表配置:
// TODO replace with your connection string
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var silo = new SiloHostBuilder()
[...]
.UseAzureTableReminderService(options => options.ConnectionString = connectionString)
[...]
SQL:
// TODO replace with your connection string
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
const string invariant = "YOUR_INVARIANT";
var silo = new SiloHostBuilder()
[...]
.UseAdoNetReminderService(options =>
{
options.ConnectionString = connectionString;
options.Invariant = invariant;
})
[...]
如果您只是想要一个实现提醒器的占位符,而不需设置Azure帐户或SQL数据库,那么这将为您提供一个仅限开发的提醒器系统实现:
var silo = new SiloHostBuilder()
[...]
.UseInMemoryReminderService()
[...]
使用提醒器的grain,必须实现IRemindable.RecieveReminder方法。
Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
Console.WriteLine("Thanks for reminding me-- I almost forgot!");
return TaskDone.Done;
}
要启动提醒器,请使用Grain.RegisterOrUpdateReminder方法,该方法返回IOrleansReminder对象:
protected Task RegisterOrUpdateReminder(string reminderName, TimeSpan dueTime, TimeSpan period)
由于提醒器在任何单次激活的生命周期中都存在,因此必须显式地取消它们(而不是被dispose)。您通过调用Grain.UnregisterReminder取消提醒器:
protected Task UnregisterReminder(IOrleansReminder reminder)
提醒器是Grain.RegisterOrUpdateReminder返回的句柄对象。
IOrleansReminder的实例不能保证在激活的生命周期之外是有效的。如果要以持续的方式标识提醒,请使用包含提醒器名称的字符串。
如果您只有提醒器名称,并且需要相应的IOrleansReminder实例 ,请调用Grain.GetReminder方法:
protected Task GetReminder(string reminderName)
我们建议您在以下情况下使用定时器:
Grain.OnActivateAsync
启动,也可以在调用一个grain方法时启动。我们建议您在以下情况下使用提醒器:
您可以考虑使用提醒器和计时器的组合来实现目的。例如,如果您需要一个在激活过程中存活下来且分辨率很小的定时器,可以使用每五分钟运行一次的提醒器,其目的是唤醒一个grain重新启动一个本地的定时器,而该定时器可能由于已停用而发生丢失。