private async Task <EtcdResponse> TolerantFetch(string requestUri) { try { EtcdResponse resp = await SendRequest(HttpMethod.Get, requestUri); if (resp != null) { return(resp); } } catch (TaskCanceledException) { // no changes detected and the connection idles for too long, try again } catch (EtcdCommonException.KeyNotFound) { } catch (HttpRequestException hrex) { // server closed connection WebException webException = hrex.InnerException as WebException; if (webException == null || webException.Status != WebExceptionStatus.ConnectionClosed) { throw; } } return(null); }
/// <summary> /// Watch changes /// </summary> /// <param name="key">Path of the node</param> /// <param name="recursive">true to monitor descendants</param> /// <param name="waitIndex">Etcd Index is continue monitor from</param> /// <returns>EtcdResponse</returns> public async Task <EtcdResponse> WatchNodeAsync(string key, bool recursive = false, long?waitIndex = null) { var requestUri = BuildRequestUri(key, recursive, waitIndex); for (; ;) { try { EtcdResponse resp = await SendRequest(HttpMethod.Get, requestUri); if (resp != null) { return(resp); } } catch (TaskCanceledException) { // no changes detected and the connection idles for too long, try again } catch (HttpRequestException hrex) { // server closed connection WebException webException = hrex.InnerException as WebException; if (webException == null || webException.Status != WebExceptionStatus.ConnectionClosed) { throw; } } } }
/// <summary> /// Watch changes /// </summary> /// <param name="key">Path of the node</param> /// <param name="recursive">true to monitor descendants</param> /// <param name="waitIndex">Etcd Index is continue monitor from</param> /// <returns>EtcdResponse</returns> public async Task <EtcdResponse> WatchNodeAsync(string key, bool recursive = false, long?waitIndex = null) { if (string.IsNullOrWhiteSpace(key)) { throw new ArgumentNullException("key"); } if (!key.StartsWith("/")) { throw new ArgumentException("The value of `key` must start with `/`."); } string requestUri = string.Format(CultureInfo.InvariantCulture , "/v2/keys{0}?wait=true&recursive={1}" , key #if NET45 , recursive.ToString(CultureInfo.InvariantCulture).ToLowerInvariant() #else , recursive.ToString().ToLowerInvariant() #endif ); if (waitIndex.HasValue) { requestUri = string.Format(CultureInfo.InvariantCulture , "{0}&waitIndex={1}" , requestUri , waitIndex.Value ); } for (; ;) { try { EtcdResponse resp = await SendRequest(HttpMethod.Get, requestUri); if (resp != null) { return(resp); } } catch (TaskCanceledException) { // no changes detected and the connection idles for too long, try again } catch (HttpRequestException hrex) { // server closed connection WebException webException = hrex.InnerException as WebException; if (webException == null || webException.Status != WebExceptionStatus.ConnectionClosed) { throw; } } } }
/// <summary> /// Simplified version of `GetNodeAsync`. /// Get the value of the specific node /// </summary> /// <param name="key">The path of the node, must start with `/`</param> /// <param name="ignoreKeyNotFoundException">If `true`, `EtcdCommonException.KeyNotFound` exception is ignored and `null` is returned instead.</param> /// <returns>A string represents a value. It could be `null`</returns> public async Task <string> GetNodeValueAsync(string key, bool ignoreKeyNotFoundException = false) { EtcdResponse getNodeResponse = await this.GetNodeAsync(key, ignoreKeyNotFoundException); if (getNodeResponse != null && getNodeResponse.Node != null) { return(getNodeResponse.Node.Value); } return(null); }
/// <summary> /// Get etcd node specified by `key` /// </summary> /// <param name="key">The path of the node, must start with `/`</param> /// <param name="recursive">Represents whether list the children nodes</param> /// <param name="sorted">To enumerate the in-order keys as a sorted list, use the "sorted" parameter.</param> /// <param name="ignoreKeyNotFoundException">If `true`, `EtcdCommonException.KeyNotFound` exception is ignored and `null` is returned instead.</param> /// <returns>represents response; or `null` if not exist</returns> public async Task <EtcdResponse> GetNodeAsync(string key , bool ignoreKeyNotFoundException = false , bool recursive = false , bool sorted = false ) { if (string.IsNullOrWhiteSpace(key)) { throw new ArgumentNullException("key"); } if (!key.StartsWith("/")) { throw new ArgumentException("The value of `key` must start with `/`."); } try { string url = string.Format(CultureInfo.InvariantCulture , "/v2/keys{0}?recursive={1}&sorted={2}" , key #if NET45 , recursive.ToString(CultureInfo.InvariantCulture).ToLowerInvariant() , sorted.ToString(CultureInfo.InvariantCulture).ToLowerInvariant() #else , recursive.ToString().ToLowerInvariant() , sorted.ToString().ToLowerInvariant() #endif ); EtcdResponse getNodeResponse = await SendRequest(HttpMethod.Get, url); return(getNodeResponse); } catch (EtcdCommonException.KeyNotFound) { if (ignoreKeyNotFoundException) { return(null); } throw; } }
private async Task <EtcdResponse> SendRequest(HttpMethod method, string requestUri, IEnumerable <KeyValuePair <string, string> > formFields = null) { HttpClientEx startClient = _currentClient; HttpClientEx currentClient = _currentClient; for (; ;) { try { using (HttpRequestMessage requestMessage = new HttpRequestMessage(method, requestUri)) { if (formFields != null) { requestMessage.Content = new FormUrlEncodedContent(formFields); } using (HttpResponseMessage responseMessage = await currentClient.SendAsync(requestMessage)) { string json = null; if (responseMessage.Content != null) { json = await responseMessage.Content.ReadAsStringAsync(); } if (!responseMessage.IsSuccessStatusCode) { if (!string.IsNullOrWhiteSpace(json)) { ErrorResponse errorResponse = null; try { errorResponse = _jsonDeserializer.Deserialize <ErrorResponse>(json); } catch { } if (errorResponse != null) { throw EtcdGenericException.Create(requestMessage, errorResponse); } } currentClient = currentClient.Next; if (currentClient != startClient) { // try the next continue; } else { responseMessage.EnsureSuccessStatusCode(); } } // if currentClient != _currentClient, update _currentClient if (currentClient != startClient) { Interlocked.CompareExchange(ref _currentClient, currentClient, startClient); } if (!string.IsNullOrWhiteSpace(json)) { EtcdResponse resp = _jsonDeserializer.Deserialize <EtcdResponse>(json); resp.EtcdServer = currentClient.BaseAddress.OriginalString; resp.EtcdClusterID = GetStringHeader(responseMessage, "X-Etcd-Cluster-Id"); resp.EtcdIndex = GetLongHeader(responseMessage, "X-Etcd-Index"); resp.RaftIndex = GetLongHeader(responseMessage, "X-Raft-Index"); resp.RaftTerm = GetLongHeader(responseMessage, "X-Raft-Term"); long previousIndex = _lastIndex; if (resp.EtcdIndex > previousIndex) { Interlocked.CompareExchange(ref _lastIndex, resp.EtcdIndex, previousIndex); } this.ClusterID = resp.EtcdClusterID; return(resp); } return(null); } } } catch (EtcdRaftException) { currentClient = currentClient.Next; if (currentClient != startClient) { continue; // try the next } else { throw; // tried all clients, all failed } } catch (EtcdGenericException) { throw; } catch (Exception) { currentClient = currentClient.Next; if (currentClient != startClient) { continue; // try the next } else { throw; // tried all clients, all failed } } } }