private async Task RefreshIndividualKeyValues() { bool shouldRefreshAll = false; foreach (KeyValueWatcher changeWatcher in _options.ChangeWatchers) { string watchedKey = changeWatcher.Key; string watchedLabel = changeWatcher.Label; var timeElapsedSinceLastRefresh = DateTimeOffset.UtcNow - changeWatcher.LastRefreshTime; // Skip the refresh for this key if the cached value has not expired or a refresh operation is in progress if (timeElapsedSinceLastRefresh < changeWatcher.CacheExpirationTime || !changeWatcher.Semaphore.Wait(0)) { continue; } try { bool hasChanged = false; ConfigurationSetting watchedKv = null; if (_settings.ContainsKey(watchedKey) && _settings[watchedKey].Label == watchedLabel.NormalizeNull()) { watchedKv = _settings[watchedKey]; KeyValueChange keyValueChange = default; await TracingUtils.CallWithRequestTracing(_requestTracingEnabled, RequestType.Watch, _hostType, async() => keyValueChange = await _client.GetKeyValueChange(watchedKv, CancellationToken.None).ConfigureAwait(false)).ConfigureAwait(false); changeWatcher.LastRefreshTime = DateTimeOffset.UtcNow; // Check if a change has been detected in the key-value registered for refresh if (keyValueChange.ChangeType != KeyValueChangeType.None) { ProcessChanges(Enumerable.Repeat(keyValueChange, 1)); hasChanged = true; } } else { // Load the key-value in case the previous load attempts had failed var options = new SettingSelector { LabelFilter = watchedLabel }; try { await CallWithRequestTracing(async() => watchedKv = await _client.GetConfigurationSettingAsync(watchedKey, watchedLabel, CancellationToken.None).ConfigureAwait(false)).ConfigureAwait(false); } catch (RequestFailedException e) when(e.Status == (int)HttpStatusCode.NotFound) { watchedKv = null; } changeWatcher.LastRefreshTime = DateTimeOffset.UtcNow; if (watchedKv != null) { // Add the key-value if it is not loaded, or update it if it was loaded with a different label _settings[watchedKey] = watchedKv; hasChanged = true; } } if (hasChanged) { if (changeWatcher.RefreshAll) { shouldRefreshAll = true; // Skip refresh for other key-values since refreshAll will populate configuration from scratch break; } else { await SetData(_settings).ConfigureAwait(false); } } } finally { changeWatcher.Semaphore.Release(); } } // Trigger a single refresh-all operation if a change was detected in one or more key-values with refreshAll: true if (shouldRefreshAll) { await LoadAll(ignoreFailures : false).ConfigureAwait(false); } }
private async Task RefreshIndividualKeyValues() { bool shouldRefreshAll = false; foreach (KeyValueWatcher changeWatcher in _options.ChangeWatchers) { string watchedKey = changeWatcher.Key; string watchedLabel = changeWatcher.Label; // Skip the refresh for this key if the cached value has not expired or a refresh operation is in progress if (DateTimeOffset.UtcNow < changeWatcher.CacheExpires || !changeWatcher.Semaphore.Wait(0)) { continue; } try { bool hasChanged = false; KeyValueIdentifier watchedKeyLabel = new KeyValueIdentifier(watchedKey, watchedLabel); if (_watchedSettings.TryGetValue(watchedKeyLabel, out ConfigurationSetting watchedKv)) { KeyValueChange keyValueChange = default; await TracingUtils.CallWithRequestTracing(_requestTracingEnabled, RequestType.Watch, _hostType, async() => keyValueChange = await _client.GetKeyValueChange(watchedKv, CancellationToken.None).ConfigureAwait(false)).ConfigureAwait(false); changeWatcher.CacheExpires = DateTimeOffset.UtcNow.Add(changeWatcher.CacheExpirationInterval); // Check if a change has been detected in the key-value registered for refresh if (keyValueChange.ChangeType != KeyValueChangeType.None) { if (changeWatcher.RefreshAll) { shouldRefreshAll = true; break; } if (keyValueChange.ChangeType == KeyValueChangeType.Deleted) { _watchedSettings.TryRemove(watchedKeyLabel, out ConfigurationSetting _); } else if (keyValueChange.ChangeType == KeyValueChangeType.Modified) { _watchedSettings[watchedKeyLabel] = keyValueChange.Current; } hasChanged = true; ProcessChanges(Enumerable.Repeat(keyValueChange, 1)); } } else { // Load the key-value in case the previous load attempts had failed var options = new SettingSelector { LabelFilter = watchedLabel }; try { await CallWithRequestTracing(async() => watchedKv = await _client.GetConfigurationSettingAsync(watchedKey, watchedLabel, CancellationToken.None).ConfigureAwait(false)).ConfigureAwait(false); } catch (RequestFailedException e) when(e.Status == (int)HttpStatusCode.NotFound) { watchedKv = null; } changeWatcher.CacheExpires = DateTimeOffset.UtcNow.Add(changeWatcher.CacheExpirationInterval); if (watchedKv != null) { if (changeWatcher.RefreshAll) { shouldRefreshAll = true; break; } hasChanged = true; // Add the key-value if it is not loaded, or update it if it was loaded with a different label _applicationSettings[watchedKey] = watchedKv; _watchedSettings[watchedKeyLabel] = watchedKv; } } if (hasChanged) { await SetData(_applicationSettings).ConfigureAwait(false); } } finally { changeWatcher.Semaphore.Release(); } } // Trigger a single refresh-all operation if a change was detected in one or more key-values with refreshAll: true if (shouldRefreshAll) { await LoadAll(ignoreFailures : false).ConfigureAwait(false); } }