/// <summary> /// Ensures workflow timers are registered for waking the instance up. /// </summary> /// <returns></returns> async Task SaveReminderAsync() { // next date at which the reminder should be invoked var dueDate = (DateTime?)state.GetInstanceData(ActivityTimerExpirationTimeKey) ?? DateTime.MinValue; if (dueDate != DateTime.MinValue) { // lock down current time var nowDate = DateTime.UtcNow; // don't allow dates in the past if (dueDate < nowDate) { dueDate = nowDate; } // unregister reminder if it the time has changed var reminder = actor.TryGetReminder(ActivityTimerExpirationReminderName); if (reminder != null) { // deserialize last due date from reminder var lastDueDate = DateTime.FromBinary(BitConverter.ToInt64(reminder.State, 0)); if (lastDueDate != dueDate) { // timer is out of range, will reschedule below await actor.UnregisterReminderAsync(reminder); reminder = null; } } // schedule new reminder if (reminder == null) { await actor.RegisterReminderAsync( ActivityTimerExpirationReminderName, BitConverter.GetBytes(dueDate.ToBinary()), (dueDate - nowDate).Max(TimeSpan.FromMilliseconds(100)), TimeSpan.FromMilliseconds(-1)); } } else { // no reminder required, unregister existing reminder var reminder = actor.TryGetReminder(ActivityTimerExpirationReminderName); if (reminder != null) { await actor.UnregisterReminderAsync(reminder); } } }
/// <summary> /// Loads the instance data for the given instance ID. /// </summary> /// <param name="instanceId"></param> /// <returns></returns> IDictionary <XName, InstanceValue> LoadInstanceData(Guid instanceId) { return(state.GetInstanceDataNames().ToDictionary(i => (XName)i, i => new InstanceValue(FromSerializableObject(state.GetInstanceData(i))))); }