计时器和提醒
Orleans运行时提供了两种机制,称为计时器和提醒,使开发人员可以指定Grains的周期性行为。
计时器
计时器说明
计时器用于创建不需要多次激活(Grains实例化)的周期性Grains行为。它与标准基本上相同。NET System.Threading.Timer类。另外,它在运行的Grains激活中要受单线程执行保证的约束。
每次激活可能具有零个或多个与其关联的计时器。运行时在与之关联的激活的运行时上下文中执行每个计时器例程。
计时器使用
要启动计时器,请使用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
通过丢弃计时器来取消它。
如果取消激活激活或发生故障并且其silos崩溃,计时器将停止触发。
重要注意事项
- 启用激活收集后,计时器回调的执行不会将激活状态从空闲更改为使用中。这意味着无法使用计时器来推迟其他情况下空闲激活的取消激活。
- 期间过去了Grain.RegisterTimer是从任务返回的那一刻起经过的时间asyncCallback解决到下一次调用asyncCallback应该发生。这不仅使得无法连续调用asyncCallback重叠但也使时间长asyncCallback完成需要影响的频率asyncCallback被调用。这与System.Threading.Timer。
- 每次调用asyncCallback将在单独的回合上传递给激活,并且永远不会与同一激活中的其他回合同时运行。请注意,asyncCallback调用不作为消息传递,因此不受消息交织语义的约束。这意味着asyncCallback相对于传递给该Grains的其他消息,应被视为表现为在ReentrantGrains上运行。
提醒事项
提醒说明
提醒与计时器类似,但有一些重要区别:
- 提醒是持久化的,除非明确取消,否则提醒将在几乎所有情况下(包括部分或完全重启群集)继续触发。
- 提醒“定义”被写入存储。但是,不是每个特定的事件及其特定的时间。这样做的副作用是,如果在某个特定的提醒滴答声时群集完全崩溃,则它将丢失,并且仅会发生提醒的下一个滴答声。
- 提醒与Grains相关联,而不是任何特定的激活。
- 如果某个Grains没有与之关联的激活并且有提示音,则将创建一个。例如:如果激活闲置而被停用,则与同一Grains关联的提醒会在下次勾选时重新激活Grains。
- 提醒是通过消息传递的,并且与其他所有grain方法都具有相同的交织语义。
- 提醒事项不应用于高频计时器,其周期应以分钟,小时或天为单位。
组态
提醒是持久的,依赖于存储来发挥作用。在提醒子系统起作用之前,您必须指定要使用的存储支持。这是通过以下方式配置提醒提供程序之一来完成的: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 Task.CompletedTask;
}
要启动提醒,请使用Grain.RegisterOrUpdateReminder方法,该方法返回一个IOrleansReminder目的:
protected Task<IOrleansReminder> RegisterOrUpdateReminder(string reminderName, TimeSpan dueTime, TimeSpan period)
- hinterName是一个字符串,必须在上下文范围内唯一地标识提醒。
- dueTime指定发出第一个计时器刻度之前要等待的时间。
- period指定计时器的时间。
由于提醒在任何一次激活的生命周期中都可以保留,因此必须将其明确取消(而不是处置)。您通过调用取消提醒Grain.UnregisterReminder:
protected Task UnregisterReminder(IOrleansReminder reminder)
提醒是返回的句柄对象Grains.RegisterOrUpdateReminder.
实例IOrleansReminder不能保证在激活的有效期之外有效。如果希望以持续的方式标识提醒,请使用包含提醒名称的字符串。
如果您只有提醒的名称并需要相应的实例IOrleansReminder,访问Grains.GetReminder方法:
protected Task<IOrleansReminder> GetReminder(string reminderName)
我应该用哪一个?
我们建议您在以下情况下使用计时器:
- 如果激活被停用或发生故障,计时器停止工作并不重要(或是可取的)。
- 计时器的分辨率很小(例如,可以用秒或分钟表示)。
- 计时器回调可以从
Grain.OnActivateAsync
或者调用grain方法时。
我们建议您在以下情况下使用提醒:
- 当周期性行为需要在激活和任何失败中幸存下来时。
- 执行一些不经常发生的任务(例如,在几分钟、几小时或几天内可以合理地表达)。
组合计时器和提醒
你可以考虑结合使用提醒和计时器来完成你的目标。例如,如果您需要一个分辨率很小的计时器,而该计时器需要在激活期间继续存在,则可以使用每五分钟运行一次的提醒,该提醒的目的是唤醒一个grains,该grains将重新启动可能因停用而丢失的本地计时器。