public AzureDiscoveryFetcher() { _discovery = new AzureDiscovery( CloudConfiguration.SubscriptionId, CloudConfiguration.GetManagementCertificate()); }
public Task<DeploymentReference> Discover(CancellationToken cancellationToken) { var client = HttpClientFactory.Create(_subscriptionId, _certificate); var completionSource = new TaskCompletionSource<DeploymentReference>(); Task<DeploymentReference> previousTask; var discovery = new AzureDiscovery(_subscriptionId, _certificate, _observer); // If we have already succeeded, just pass on the result from the last time (shortcut) lock (_currentDeploymentDiscoveryLock) { if (_currentDeployment != null) { completionSource.TrySetResult(_currentDeployment); return completionSource.Task; } previousTask = _currentDeploymentDiscoveryTask; _currentDeploymentDiscoveryTask = completionSource.Task; } // If this is the first time this is called, create a new query and return if (previousTask == null) { discovery.DoDiscoverDeploymentAsync(client, _deploymentPrivateId, completionSource, cancellationToken); completionSource.Task.ContinueRaiseSystemEventOnFault(_observer, AzureDiscovery.EventForFailedOperation); return completionSource.Task; } // We have already called but have not got the result yet. // In case there is already a task running (this is likely in our scenarios) wait for the result. // Retry once in case it will fail, or, more importantly, if it has already failed (the last time). previousTask.ContinueWith(task => { try { if (task.IsFaulted || (task.IsCanceled && !cancellationToken.IsCancellationRequested)) { discovery.DoDiscoverDeploymentAsync(client, _deploymentPrivateId, completionSource, cancellationToken); completionSource.Task.ContinueRaiseSystemEventOnFault(_observer, AzureDiscovery.EventForFailedOperation); return; } if (task.IsCanceled) { completionSource.TrySetCanceled(); return; } completionSource.TrySetResult(task.Result); } catch (Exception exception) { // this should never happen, so forward but do not try to handle/retry here. completionSource.TrySetException(exception); } }, TaskContinuationOptions.ExecuteSynchronously); // NOTE: _currentDeployment may not be available yet in other continuations. This is ok. completionSource.Task.ContinueWith(t => { lock (_currentDeploymentDiscoveryLock) { _currentDeployment = t.Result; } }, TaskContinuationOptions.OnlyOnRanToCompletion); return completionSource.Task; }