File: System\Activities\DurableInstancing\PersistenceTask.cs
Project: ndp\cdf\src\NetFx40\System.Activities.DurableInstancing\System.Activities.DurableInstancing.csproj (System.Activities.DurableInstancing)
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------
 
namespace System.Activities.DurableInstancing
{
    using System;
    using System.Runtime;
    using System.Runtime.DurableInstancing;
 
    abstract class PersistenceTask
    {
        bool automaticallyResetTimer;
        AsyncCallback commandCompletedCallback;
        InstancePersistenceCommand instancePersistenceCommand;
        TimeSpan taskInterval;
        IOThreadTimer taskTimer;
        object thisLock;
        bool timerCancelled;
        TimeSpan taskTimeout;
 
        public PersistenceTask(SqlWorkflowInstanceStore store, SqlWorkflowInstanceStoreLock storeLock, InstancePersistenceCommand instancePersistenceCommand, TimeSpan taskInterval, TimeSpan taskTimeout, bool automaticallyResetTimer)
        {
            this.automaticallyResetTimer = automaticallyResetTimer;
            this.commandCompletedCallback = Fx.ThunkCallback(CommandCompletedCallback);
            this.instancePersistenceCommand = instancePersistenceCommand;
            this.Store = store;
            this.StoreLock = storeLock;
            this.SurrogateLockOwnerId = this.StoreLock.SurrogateLockOwnerId;
            this.taskInterval = taskInterval;        
            this.thisLock = new object();
            this.taskTimeout = taskTimeout;
        }
 
        protected SqlWorkflowInstanceStore Store
        {
            get;
            set;
        }
 
        protected SqlWorkflowInstanceStoreLock StoreLock
        {
            get;
            set;
        }
 
        protected long SurrogateLockOwnerId
        {
            get;
            set;
        }
 
        object ThisLock
        {
            get
            {
                return this.thisLock;
            }
        }
 
        public void CancelTimer()
        {
            lock (ThisLock)
            {
                this.timerCancelled = true;
 
                if (this.taskTimer != null)
                {
                    this.taskTimer.Cancel();
                    this.taskTimer = null;
                }
            }
        }
 
        public void ResetTimer(bool fireImmediately)
        {
            this.ResetTimer(fireImmediately, null);
        }
 
        public virtual void ResetTimer(bool fireImmediately, TimeSpan? taskIntervalOverride)
        {
            TimeSpan timeTillNextPoll = this.taskInterval;
 
            if (taskIntervalOverride.HasValue)
            {
                if (taskIntervalOverride.Value < this.taskInterval)
                    timeTillNextPoll = taskIntervalOverride.Value;
            }
 
            lock (ThisLock)
            {
                if (!this.timerCancelled)
                {
                    if (this.taskTimer == null)
                    {
                        this.taskTimer = new IOThreadTimer(new Action<object>(this.OnTimerFired), null, false);
                    }
 
                    this.taskTimer.Set(fireImmediately ? TimeSpan.Zero : timeTillNextPoll);
                }
            }
        }
 
        protected abstract void HandleError(Exception exception);
 
        void CommandCompletedCallback(IAsyncResult result)
        {
            SqlWorkflowInstanceStoreAsyncResult sqlResult = (SqlWorkflowInstanceStoreAsyncResult) result;
 
            try
            {
                this.Store.EndTryCommand(result);
 
                if (this.automaticallyResetTimer)
                {
                    this.ResetTimer(false);
                }
            }
            catch (Exception exception)
            {
                if (Fx.IsFatal(exception))
                {
                    throw;
                }
 
                HandleError(exception);
            }
        }
 
        void OnTimerFired(object state)
        {
            if (this.StoreLock.IsLockOwnerValid(this.SurrogateLockOwnerId))
            {
                try
                {
                    this.Store.BeginTryCommandSkipRetry(null, this.instancePersistenceCommand, this.taskTimeout,
                        this.commandCompletedCallback, null);
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw;
                    }
 
                    this.HandleError(exception);
                }
            }
        }
    }
}