11
11
// limitations under the License.
12
12
// ------------------------------------------------------------------------
13
13
14
+ using System ;
15
+ using System ;
14
16
using System . Reflection ;
15
17
using System . Text . Json ;
18
+ using System . Threading ;
16
19
using Grpc . Net . Client ;
17
20
using Microsoft . Extensions . Configuration ;
18
21
@@ -31,6 +34,11 @@ protected DaprGenericClientBuilder(IConfiguration? configuration = null)
31
34
this . GrpcEndpoint = DaprDefaults . GetDefaultGrpcEndpoint ( ) ;
32
35
this . HttpEndpoint = DaprDefaults . GetDefaultHttpEndpoint ( ) ;
33
36
37
+ this . GrpcKeepAliveEnabled = DaprDefaults . GetDefaultGrpcKeepAliveEnable ( configuration ) ;
38
+ this . GrpcKeepAliveTime = TimeSpan . FromSeconds ( DaprDefaults . GetDefaultGrpcKeepAliveTimeSeconds ( configuration ) ) ;
39
+ this . GrpcKeepAliveTimeout = TimeSpan . FromSeconds ( DaprDefaults . GetDefaultGrpcKeepAliveTimeoutSeconds ( configuration ) ) ;
40
+ this . GrpcKeepAlivePermitWithoutCalls = DaprDefaults . GetDefaultGrpcKeepAliveWithoutCalls ( configuration ) ;
41
+
34
42
this . GrpcChannelOptions = new GrpcChannelOptions ( )
35
43
{
36
44
// The gRPC client doesn't throw the right exception for cancellation
@@ -71,12 +79,32 @@ protected DaprGenericClientBuilder(IConfiguration? configuration = null)
71
79
/// Property exposed for testing purposes.
72
80
/// </summary>
73
81
public string DaprApiToken { get ; private set ; }
74
-
82
+
75
83
/// <summary>
76
84
/// Property exposed for testing purposes.
77
85
/// </summary>
78
86
internal TimeSpan Timeout { get ; private set ; }
79
87
88
+ /// <summary>
89
+ /// Property exposed for testing purposes.
90
+ /// </summary>
91
+ internal bool GrpcKeepAliveEnabled { get ; private set ; }
92
+
93
+ /// <summary>
94
+ /// Property exposed for testing purposes.
95
+ /// </summary>
96
+ internal TimeSpan GrpcKeepAliveTime { get ; private set ; }
97
+
98
+ /// <summary>
99
+ /// Property exposed for testing purposes.
100
+ /// </summary>
101
+ internal TimeSpan GrpcKeepAliveTimeout { get ; private set ; }
102
+
103
+ /// <summary>
104
+ /// Property exposed for testing purposes.
105
+ /// </summary>
106
+ internal bool GrpcKeepAlivePermitWithoutCalls { get ; private set ; }
107
+
80
108
/// <summary>
81
109
/// Overrides the HTTP endpoint used by the Dapr client for communicating with the Dapr runtime.
82
110
/// </summary>
@@ -180,6 +208,50 @@ public DaprGenericClientBuilder<TClientBuilder> UseTimeout(TimeSpan timeout)
180
208
return this ;
181
209
}
182
210
211
+ /// <summary>
212
+ /// Enables or disables gRPC keep-alive.
213
+ /// </summary>
214
+ /// <param name="enabled">Whether to enable gRPC keep-alive.</param>
215
+ /// <returns>The <see cref="DaprGenericClientBuilder{TClientBuilder}" /> instance.</returns>
216
+ public DaprGenericClientBuilder < TClientBuilder > UseGrpcKeepAlive ( bool enabled )
217
+ {
218
+ this . GrpcKeepAliveEnabled = enabled ;
219
+ return this ;
220
+ }
221
+
222
+ /// <summary>
223
+ /// Sets the gRPC keep-alive time interval.
224
+ /// </summary>
225
+ /// <param name="keepAliveTime">The time interval between keep-alive pings.</param>
226
+ /// <returns>The <see cref="DaprGenericClientBuilder{TClientBuilder}" /> instance.</returns>
227
+ public DaprGenericClientBuilder < TClientBuilder > UseGrpcKeepAliveTime ( TimeSpan keepAliveTime )
228
+ {
229
+ this . GrpcKeepAliveTime = keepAliveTime ;
230
+ return this ;
231
+ }
232
+
233
+ /// <summary>
234
+ /// Sets the gRPC keep-alive timeout.
235
+ /// </summary>
236
+ /// <param name="keepAliveTimeout">The time to wait for a keep-alive ping response before considering the connection dead.</param>
237
+ /// <returns>The <see cref="DaprGenericClientBuilder{TClientBuilder}" /> instance.</returns>
238
+ public DaprGenericClientBuilder < TClientBuilder > UseGrpcKeepAliveTimeout ( TimeSpan keepAliveTimeout )
239
+ {
240
+ this . GrpcKeepAliveTimeout = keepAliveTimeout ;
241
+ return this ;
242
+ }
243
+
244
+ /// <summary>
245
+ /// Sets whether gRPC keep-alive should be sent when there are no active calls.
246
+ /// </summary>
247
+ /// <param name="permitWithoutCalls">Whether to send keep-alive pings even when there are no active calls.</param>
248
+ /// <returns>The <see cref="DaprGenericClientBuilder{TClientBuilder}" /> instance.</returns>
249
+ public DaprGenericClientBuilder < TClientBuilder > UseGrpcKeepAlivePermitWithoutCalls ( bool permitWithoutCalls )
250
+ {
251
+ this . GrpcKeepAlivePermitWithoutCalls = permitWithoutCalls ;
252
+ return this ;
253
+ }
254
+
183
255
/// <summary>
184
256
/// Builds out the inner DaprClient that provides the core shape of the
185
257
/// runtime gRPC client used by the consuming package.
@@ -209,8 +281,25 @@ protected internal (GrpcChannel channel, HttpClient httpClient, Uri httpEndpoint
209
281
//Configure the HTTP client
210
282
var httpClient = ConfigureHttpClient ( assembly ) ;
211
283
this . GrpcChannelOptions . HttpClient = httpClient ;
284
+
285
+ if ( this . GrpcKeepAliveEnabled )
286
+ {
287
+ if ( ! ( this . GrpcChannelOptions . HttpHandler is SocketsHttpHandler ) )
288
+ {
289
+ var handler = new SocketsHttpHandler ( ) ;
290
+ this . GrpcChannelOptions . HttpHandler = handler ;
291
+ }
292
+
293
+ var socketsHandler = ( SocketsHttpHandler ) this . GrpcChannelOptions . HttpHandler ;
294
+
295
+ socketsHandler . KeepAlivePingDelay = this . GrpcKeepAliveTime ;
296
+ socketsHandler . KeepAlivePingTimeout = this . GrpcKeepAliveTimeout ;
297
+ socketsHandler . KeepAlivePingPolicy = this . GrpcKeepAlivePermitWithoutCalls
298
+ ? HttpKeepAlivePingPolicy . Always
299
+ : HttpKeepAlivePingPolicy . WithActiveRequests ;
300
+ }
212
301
213
- var channel = GrpcChannel . ForAddress ( this . GrpcEndpoint , this . GrpcChannelOptions ) ;
302
+ var channel = GrpcChannel . ForAddress ( this . GrpcEndpoint , this . GrpcChannelOptions ) ;
214
303
return ( channel , httpClient , httpEndpoint , this . DaprApiToken ) ;
215
304
}
216
305
@@ -222,17 +311,17 @@ protected internal (GrpcChannel channel, HttpClient httpClient, Uri httpEndpoint
222
311
private HttpClient ConfigureHttpClient ( Assembly assembly )
223
312
{
224
313
var httpClient = HttpClientFactory is not null ? HttpClientFactory ( ) : new HttpClient ( ) ;
225
-
314
+
226
315
//Set the timeout as necessary
227
316
if ( this . Timeout > TimeSpan . Zero )
228
317
{
229
318
httpClient . Timeout = this . Timeout ;
230
319
}
231
-
320
+
232
321
//Set the user agent
233
322
var userAgent = DaprClientUtilities . GetUserAgent ( assembly ) ;
234
323
httpClient . DefaultRequestHeaders . Add ( "User-Agent" , userAgent . ToString ( ) ) ;
235
-
324
+
236
325
//Set the API token
237
326
var apiTokenHeader = DaprClientUtilities . GetDaprApiTokenHeader ( this . DaprApiToken ) ;
238
327
if ( apiTokenHeader is not null )
0 commit comments