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 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; }; }