Timers and Reminder 定时器和提醒器

Orleans runtime 允许开发人员通过一种叫做timer和另一种叫做reminder的机制为grain添加周期性行为。接下来我分别为大家介绍Timer和Reminder

Timers 定时器

   Timer用于创建grain的定时任务,但这个定时任务并非跨实例的(StateLessWorker允许多个实例)周期性任务,类似于System.Threading.Timer,但不同的是,它需要它依赖的grain实例来保证单线程执行模式

   使用方式

    RegisterTimer会返回一个IDisposable引用,你可以通过调用dispose来取消这个timer

protected IDisposable RegisterTimer(Func<object, Task> asyncCallback, object state, TimeSpan dueTime, TimeSpan period)

几个注意事项

  1.    Timer定时调用不会改变当前grain实例的状态(grain实例状态:空闲 idle、使用中use),如果你通过Timer来延迟grian因为空闲太久而被回收 (从idle到use状态装换),是行不通的。也就是说即使有timer,如果这个grain一直没有被调用过,这个grain可能会因为空闲太久而被转 为非激活状态,timer就不在继续运行

  2.    Timer的周期,指的是从上一次的调用成功后,到下次调用开始前的一段时间,Orleans的Timer不仅不会发生类似于System.Theading.Timer的重叠调用,而且延长调用周期为【固定的周期+上一次调用的时间】

  3.    Timer的调用,不会和这个grain上的其它调用并行执行。而且asyncCallback不会想其它调用一样做为消息传递

Reminders 提醒器

   Reminder和Timer有几个不同之处:

  1. Reminder会持久化存储自身,也就是重启Orleans,不会导致Reminder失效,它会持续运行

  2. Reminder是针对Grain,而不是Grain的特定实例

  3. 如果在Reminder到期提醒时,没有任何这个Grain的激活实例,它会创建一个新的激活实例

  4. Reminder的调用时通过消息,在调用方式上,和grain的其它方法调用相同

  5. Reminder不要使用在高频率的调用上,调用周期应该是分钟、小时、或者日级别的,高频率、短周期的调用,应优先考虑Timer

   Reminder的配置

             Reminder是一个持久化的提醒,需要后端的存储支持,这个存储支持,是Orleans 服务器端的配置文件中的SystemStore配置节点中配置决定的,目前支持AzureTable和SQl SERVER。Orleans官方博客介绍说,会在2015年初开源,等开源了,我想各种第三方的SystemStoreProvider也就不是什么问 题了,只要你原因,你可以写出任何Provider。

              如果在开发环境使用,只需要暂时的保留在内存中,可以配置

<ReminderService ReminderServiceType="ReminderTableGrain"/>

   使用方式 

               要使用reminder,必须让你的grain继承IRemindable,并实现它的IRemindable.RecieveReminder 方法

Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
    Console.WriteLine("Thanks for reminding me-- I almost forgot!");    return TaskDone.Done;
}

      然后在Grain内部 需要建立提醒(Reminder)的地方,使用调用grain父类的方法

protected Task<IOrleansReminder> RegisterOrUpdateReminder(string reminderName, TimeSpan dueTime, TimeSpan period)

     参数说明:

                           reminderName reminder名称,在这个grain内部,需要是唯一的   

                           duetime         第一次调用提醒的时间间隔(从建立到第一次调用)

                           period           每次调用的周期

                取消提醒 cancel reminder

                            你可以通过调用父类的UnregisterReminder方法来完成.那么在取消之前如何得到这个reminder呢?

                             ①RegisterOrUpdateReminder会返回Reminder的引用 ②通过reminderName,通过父类的GetReminder方法


protected Task UnregisterReminder(IOrleansReminder reminder)
protected Task<IOrleansReminder> GetReminder(string reminderName)

PS:Reminder是一个非常不错的东西,稍后我会在之后的博文中,介绍如何使用Reminder来保证非持久化消息分布式系统的可靠性