Inheritance: IDisposable
 public static void DoEvery(CloudBlob blob, TimeSpan interval, Action action)
 {
     while (true)
     {
         var lastPerformed = DateTimeOffset.MinValue;
         using (var arl = new AutoRenewLease(blob))
         {
             if (arl.HasLease)
             {
                 blob.FetchAttributes();
                 DateTimeOffset.TryParseExact(blob.Metadata["lastPerformed"], "R", CultureInfo.CurrentCulture, DateTimeStyles.AdjustToUniversal, out lastPerformed);
                 if (DateTimeOffset.UtcNow >= lastPerformed + interval)
                 {
                     action();
                     lastPerformed = DateTimeOffset.UtcNow;
                     blob.Metadata["lastPerformed"] = lastPerformed.ToString("R");
                     blob.SetMetadata(arl.leaseId);
                 }
             }
         }
         var timeLeft = (lastPerformed + interval) - DateTimeOffset.UtcNow;
         var minimum = TimeSpan.FromSeconds(5); // so we're not polling the leased blob too fast
         Thread.Sleep(
             timeLeft > minimum
             ? timeLeft
             : minimum);
     }
 }
 public static void DoEvery(CloudBlob blob, TimeSpan interval, Action action)
 {
     while (true)
     {
         var lastPerformed = DateTimeOffset.MinValue;
         using (var arl = new AutoRenewLease(blob))
         {
             if (arl.HasLease)
             {
                 blob.FetchAttributes();
                 DateTimeOffset.TryParseExact(blob.Metadata["lastPerformed"], "R", CultureInfo.CurrentCulture, DateTimeStyles.AdjustToUniversal, out lastPerformed);
                 if (DateTimeOffset.UtcNow >= lastPerformed + interval)
                 {
                     action();
                     lastPerformed = DateTimeOffset.UtcNow;
                     blob.Metadata["lastPerformed"] = lastPerformed.ToString("R");
                     blob.SetMetadata(arl.leaseId);
                 }
             }
         }
         var timeLeft = (lastPerformed + interval) - DateTimeOffset.UtcNow;
         var minimum  = TimeSpan.FromSeconds(5); // so we're not polling the leased blob too fast
         Thread.Sleep(
             timeLeft > minimum
             ? timeLeft
             : minimum);
     }
 }
 public static void DoOnce(CloudBlob blob, Action action, TimeSpan pollingFrequency)
 {
     // blob.Exists has the side effect of calling blob.FetchAttributes, which populates the metadata collection
     while (!blob.Exists() || blob.Metadata["progress"] != "done")
     {
         using (var arl = new AutoRenewLease(blob))
         {
             if (arl.HasLease)
             {
                 action();
                 blob.Metadata["progress"] = "done";
                 blob.SetMetadata(arl.leaseId);
             }
             else
             {
                 Thread.Sleep(pollingFrequency);
             }
         }
     }
 }
 public static void DoOnce(CloudBlob blob, Action action, TimeSpan pollingFrequency)
 {
     // blob.Exists has the side effect of calling blob.FetchAttributes, which populates the metadata collection
     while (!blob.Exists() || blob.Metadata["progress"] != "done")
     {
         using (var arl = new AutoRenewLease(blob))
         {
             if (arl.HasLease)
             {
                 action();
                 blob.Metadata["progress"] = "done";
                 blob.SetMetadata(arl.leaseId);
             }
             else
             {
                 Thread.Sleep(pollingFrequency);
             }
         }
     }
 }
        public void Calculate()
        {
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) => {
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
            });

            var acct = CloudStorageAccount.FromConfigurationSetting("StorageConnectionString");
            var client = acct.CreateCloudBlobClient();
            var taskBlob = client.GetBlobReference("dev-task-blobs/fib-task-blob");
            var autoRenew = new AutoRenewLease(taskBlob);

            if (autoRenew.HasLease) {

                var cancellationSource = new CancellationTokenSource();
                var cancellationToken = cancellationSource.Token;
                var calculatorState = new CalculatorState { MaxNumbersInSequence = 48};

                var calculatorTask = Task.Factory.StartNew<CalculatorResult>((state) => {

                    isCalculating = true;
                    cancellationToken.ThrowIfCancellationRequested();

                    var cs = (CalculatorState)state;
                    var calculatorResult = new CalculatorResult();
                    Func<int, int> fib = null;
                    fib = number => number > 1 ? fib(number - 1) + fib(number - 2) : number;

                    while (autoRenew.HasLease && isCalculating && !cancellationToken.IsCancellationRequested) {
                        for (int i = 0; i < cs.MaxNumbersInSequence; i++) {
                            if (!autoRenew.HasLease) {
                                isCalculating = false;
                                Trace.WriteLine("autoRenew.HasLease is false.  Breaking out of calculation routine.");
                                cancellationSource.Cancel();
                                break;
                            }
                            else {
                                var nextNumber = fib(i);
                                calculatorResult.Numbers.Add(nextNumber);
                                Trace.WriteLine(String.Format("ix:{0} - {1}", (i + 1), nextNumber));
                            }
                        }

                        isCalculating = false;
                    }

                    autoRenew.Dispose();
                    cancellationToken.ThrowIfCancellationRequested();
                    return calculatorResult;

                }, calculatorState, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default);

                calculatorTask.ContinueWith(CompletedAction(autoRenew), cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);

                calculatorTask.ContinueWith(ErrorAction(autoRenew), TaskContinuationOptions.OnlyOnFaulted);
            }
        }
        private Action<Task<CalculatorResult>> ErrorAction(AutoRenewLease autoRenew)
        {
            return (task) => {
                task.Exception.Handle((inner) => {
                    if (inner is OperationCanceledException) {
                        autoRenew.Dispose();
                        Trace.WriteLine("Calculation Canceled");
                    }
                    else {
                        Trace.WriteLine("Unhandled exception when calculating the fibonacci sequence...", UnwindException(inner));
                    }

                    isCalculating = false;
                    return true;
                });
            };
        }
        private Action<Task<CalculatorResult>> CompletedAction(AutoRenewLease autoRenew)
        {
            return (task) => {
                autoRenew.Dispose();
                Trace.WriteLine("Calculation is complete...");
                Trace.WriteLine("Last number in the sequence is: " + task.Result.Numbers.Last());

                isCalculating = false;
            };
        }