@@ -56,8 +56,8 @@ public Kubernetes(KubernetesClientConfiguration config, HttpClient httpClient, b
56
56
/// Optional. The delegating handlers to add to the http client pipeline.
57
57
/// </param>
58
58
public Kubernetes ( KubernetesClientConfiguration config , params DelegatingHandler [ ] handlers )
59
- : this ( handlers )
60
59
{
60
+ CreateHttpClient ( handlers ) ;
61
61
ValidateConfig ( config ) ;
62
62
this . config = config ;
63
63
InitializeFromConfig ( ) ;
@@ -77,6 +77,18 @@ public KubernetesScheme Scheme
77
77
}
78
78
}
79
79
80
+ // TODO: uncomment if we update to a later version of Microsoft.Rest.ClientRuntime
81
+ /*/// <inheritdoc/>
82
+ protected override DelegatingHandler CreateHttpHandlerPipeline(HttpClientHandler httpClientHandler, params DelegatingHandler[] handlers)
83
+ {
84
+ HttpMessageHandler rootHandler = RemoveRetryHandler(base.CreateHttpHandlerPipeline(httpClientHandler, handlers));
85
+ return rootHandler as DelegatingHandler ?? new ForwardingHandler(rootHandler);
86
+ }
87
+
88
+ private sealed class ForwardingHandler : DelegatingHandler
89
+ {
90
+ public ForwardingHandler(HttpMessageHandler handler) : base(handler) { }
91
+ }*/
80
92
81
93
private void ValidateConfig ( KubernetesClientConfiguration config )
82
94
{
@@ -171,15 +183,21 @@ partial void CustomInitialize()
171
183
#if NET452
172
184
ServicePointManager . SecurityProtocol |= SecurityProtocolType . Tls12 ;
173
185
#endif
186
+ FirstMessageHandler = RemoveRetryHandler ( FirstMessageHandler ) ;
174
187
AppendDelegatingHandler < WatcherDelegatingHandler > ( ) ;
175
188
DeserializationSettings . Converters . Add ( new V1Status . V1StatusObjectViewConverter ( ) ) ;
176
189
}
177
190
178
191
private void AppendDelegatingHandler < T > ( ) where T : DelegatingHandler , new ( )
179
192
{
180
193
var cur = FirstMessageHandler as DelegatingHandler ;
194
+ if ( cur == null )
195
+ {
196
+ FirstMessageHandler = new T ( ) { InnerHandler = FirstMessageHandler } ;
197
+ return ;
198
+ }
181
199
182
- while ( cur != null )
200
+ do
183
201
{
184
202
var next = cur . InnerHandler as DelegatingHandler ;
185
203
@@ -195,7 +213,52 @@ partial void CustomInitialize()
195
213
}
196
214
197
215
cur = next ;
216
+ } while ( cur != null ) ;
217
+ }
218
+
219
+ // NOTE: this method replicates the logic that the base ServiceClient uses except that it doesn't insert the RetryDelegatingHandler.
220
+ // (see RemoveRetryHandler below for why we don't want it.) it seems that depending on your framework version and/or
221
+ // Microsoft.Rest.ClientRuntime version and/or which constructor gets called, there are at least two ways that the retry handler
222
+ // gets added: 1) when the HTTP client is constructed (handled here), 2) in CreateHttpHandlerPipeline (handled in an override), and
223
+ // possibly 3) based on the handlers set in CustomInitialize
224
+ private void CreateHttpClient ( DelegatingHandler [ ] handlers )
225
+ {
226
+ FirstMessageHandler = HttpClientHandler = CreateRootHandler ( ) ;
227
+ if ( handlers != null )
228
+ {
229
+ for ( int i = handlers . Length - 1 ; i >= 0 ; i -- )
230
+ {
231
+ DelegatingHandler handler = handlers [ i ] ;
232
+ while ( handler . InnerHandler is DelegatingHandler d ) handler = d ;
233
+ handler . InnerHandler = FirstMessageHandler ;
234
+ FirstMessageHandler = handlers [ i ] ;
235
+ }
236
+ }
237
+ HttpClient = new HttpClient ( FirstMessageHandler , false ) ;
238
+ }
239
+
240
+ /// <summary>Removes the retry handler added by the Microsoft.Rest.ClientRuntime.</summary>
241
+ // NOTE: we remove the RetryDelegatingHandler for two reasons. first, it has a very broad definition of what's considered a failed
242
+ // request. it considers everything outside 2xx to be failed, including 1xx (e.g. 101 Switching Protocols) and 3xx. and, it wants to
243
+ // retry 4xx errors, almost none of which are really retriable except 429 Too Many Requests and /maybe/ 423 Locked (but we're not
244
+ // dealing with WebDAV here). really, i don't think we want retry in a Kubernetes client, and as for 429 Too Many Requests, there's
245
+ // already a separate RetryAfterDelegatingHandler installed to handle 429 requests. a further problem with the RetryDelegatingHandler
246
+ // is that upon seeing a non-2xx status code it tries to read the entire response body as a string. this doesn't work well with
247
+ // streaming responses like watches and upgraded (SPDY / web socket) connections.
248
+ private HttpMessageHandler RemoveRetryHandler ( HttpMessageHandler rootHandler )
249
+ {
250
+ for ( DelegatingHandler prev = null , handler = rootHandler as DelegatingHandler ; handler != null ; )
251
+ {
252
+ if ( handler is RetryDelegatingHandler )
253
+ {
254
+ if ( prev == null ) rootHandler = handler . InnerHandler ; // if 'handler' is at the head of the chain, just return the next item
255
+ else prev . InnerHandler = handler . InnerHandler ; // otherwise, unlink 'handler' from the chain
256
+ break ;
257
+ }
258
+ prev = handler ;
259
+ handler = handler . InnerHandler as DelegatingHandler ;
198
260
}
261
+ return rootHandler ;
199
262
}
200
263
201
264
/// <summary>
0 commit comments