3232import java .net .InetAddress ;
3333import java .net .InetSocketAddress ;
3434import java .net .Socket ;
35+ import java .time .Duration ;
36+ import java .util .concurrent .TimeUnit ;
3537import java .util .regex .Pattern ;
3638
39+ import static io .dapr .config .Properties .GRPC_ENABLE_KEEP_ALIVE ;
3740import static io .dapr .config .Properties .GRPC_ENDPOINT ;
41+ import static io .dapr .config .Properties .GRPC_KEEP_ALIVE_TIMEOUT_SECONDS ;
42+ import static io .dapr .config .Properties .GRPC_KEEP_ALIVE_TIME_SECONDS ;
43+ import static io .dapr .config .Properties .GRPC_KEEP_ALIVE_WITHOUT_CALLS ;
3844import static io .dapr .config .Properties .GRPC_PORT ;
3945import static io .dapr .config .Properties .GRPC_TLS_CA_PATH ;
4046import static io .dapr .config .Properties .GRPC_TLS_CERT_PATH ;
@@ -68,8 +74,8 @@ public final class NetworkUtils {
6874
6975 private static final String GRPC_ENDPOINT_HOSTNAME_REGEX_PART = "(([A-Za-z0-9_\\ -\\ .]+)|(\\ [" + IPV6_REGEX + "\\ ]))" ;
7076
71- private static final String GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART =
72- "(?<dnsWithAuthority>dns://) (?<authorityEndpoint>"
77+ private static final String GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART = "(?<dnsWithAuthority>dns://)"
78+ + " (?<authorityEndpoint>"
7379 + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ":[0-9]+)?/" ;
7480
7581 private static final String GRPC_ENDPOINT_PARAM_REGEX_PART = "(\\ ?(?<param>tls\\ =((true)|(false))))?" ;
@@ -140,11 +146,19 @@ public static ManagedChannel buildGrpcManagedChannel(Properties properties, Clie
140146 if (interceptors != null && interceptors .length > 0 ) {
141147 builder = builder .intercept (interceptors );
142148 }
149+
150+ if (settings .enableKeepAlive ) {
151+ builder .keepAliveTime (settings .keepAliveTimeSeconds .toSeconds (), TimeUnit .SECONDS )
152+ .keepAliveTimeout (settings .keepAliveTimeoutSeconds .toSeconds (), TimeUnit .SECONDS )
153+ .keepAliveWithoutCalls (settings .keepAliveWithoutCalls );
154+ }
155+
143156 return builder .build ();
144157 } catch (Exception e ) {
145158 throw new DaprException (
146159 new DaprError ().setErrorCode ("TLS_CREDENTIALS_ERROR" )
147- .setMessage ("Failed to create insecure TLS credentials" ), e );
160+ .setMessage ("Failed to create insecure TLS credentials" ),
161+ e );
148162 }
149163 }
150164
@@ -155,23 +169,24 @@ public static ManagedChannel buildGrpcManagedChannel(Properties properties, Clie
155169 ManagedChannelBuilder <?> builder = ManagedChannelBuilder .forTarget (settings .endpoint );
156170
157171 if (clientCertPath != null && clientKeyPath != null ) {
158- // mTLS case - using client cert and key, with optional CA cert for server authentication
172+ // mTLS case - using client cert and key, with optional CA cert for server
173+ // authentication
159174 try (
160175 InputStream clientCertInputStream = new FileInputStream (clientCertPath );
161176 InputStream clientKeyInputStream = new FileInputStream (clientKeyPath );
162- InputStream caCertInputStream = caCertPath != null ? new FileInputStream (caCertPath ) : null
163- ) {
177+ InputStream caCertInputStream = caCertPath != null ? new FileInputStream (caCertPath ) : null ) {
164178 TlsChannelCredentials .Builder builderCreds = TlsChannelCredentials .newBuilder ()
165- .keyManager (clientCertInputStream , clientKeyInputStream ); // For client authentication
179+ .keyManager (clientCertInputStream , clientKeyInputStream ); // For client authentication
166180 if (caCertInputStream != null ) {
167- builderCreds .trustManager (caCertInputStream ); // For server authentication
181+ builderCreds .trustManager (caCertInputStream ); // For server authentication
168182 }
169183 ChannelCredentials credentials = builderCreds .build ();
170184 builder = Grpc .newChannelBuilder (settings .endpoint , credentials );
171185 } catch (IOException e ) {
172186 throw new DaprException (
173187 new DaprError ().setErrorCode ("TLS_CREDENTIALS_ERROR" )
174- .setMessage ("Failed to create mTLS credentials" + (caCertPath != null ? " with CA cert" : "" )), e );
188+ .setMessage ("Failed to create mTLS credentials" + (caCertPath != null ? " with CA cert" : "" )),
189+ e );
175190 }
176191 } else if (caCertPath != null ) {
177192 // Simple TLS case - using CA cert only for server authentication
@@ -183,7 +198,8 @@ public static ManagedChannel buildGrpcManagedChannel(Properties properties, Clie
183198 } catch (IOException e ) {
184199 throw new DaprException (
185200 new DaprError ().setErrorCode ("TLS_CREDENTIALS_ERROR" )
186- .setMessage ("Failed to create TLS credentials with CA cert" ), e );
201+ .setMessage ("Failed to create TLS credentials with CA cert" ),
202+ e );
187203 }
188204 } else if (!settings .secure ) {
189205 builder = builder .usePlaintext ();
@@ -194,6 +210,13 @@ public static ManagedChannel buildGrpcManagedChannel(Properties properties, Clie
194210 if (interceptors != null && interceptors .length > 0 ) {
195211 builder = builder .intercept (interceptors );
196212 }
213+
214+ if (settings .enableKeepAlive ) {
215+ builder .keepAliveTime (settings .keepAliveTimeSeconds .toSeconds (), TimeUnit .SECONDS )
216+ .keepAliveTimeout (settings .keepAliveTimeoutSeconds .toSeconds (), TimeUnit .SECONDS )
217+ .keepAliveWithoutCalls (settings .keepAliveWithoutCalls );
218+ }
219+
197220 return builder .build ();
198221 }
199222
@@ -205,13 +228,24 @@ static final class GrpcEndpointSettings {
205228 final String tlsCertPath ;
206229 final String tlsCaPath ;
207230
231+ final boolean enableKeepAlive ;
232+ final Duration keepAliveTimeSeconds ;
233+ final Duration keepAliveTimeoutSeconds ;
234+ final boolean keepAliveWithoutCalls ;
235+
208236 private GrpcEndpointSettings (
209- String endpoint , boolean secure , String tlsPrivateKeyPath , String tlsCertPath , String tlsCaPath ) {
237+ String endpoint , boolean secure , String tlsPrivateKeyPath , String tlsCertPath , String tlsCaPath ,
238+ boolean enableKeepAlive , Duration keepAliveTimeSeconds , Duration keepAliveTimeoutSeconds ,
239+ boolean keepAliveWithoutCalls ) {
210240 this .endpoint = endpoint ;
211241 this .secure = secure ;
212242 this .tlsPrivateKeyPath = tlsPrivateKeyPath ;
213243 this .tlsCertPath = tlsCertPath ;
214244 this .tlsCaPath = tlsCaPath ;
245+ this .enableKeepAlive = enableKeepAlive ;
246+ this .keepAliveTimeSeconds = keepAliveTimeSeconds ;
247+ this .keepAliveTimeoutSeconds = keepAliveTimeoutSeconds ;
248+ this .keepAliveWithoutCalls = keepAliveWithoutCalls ;
215249 }
216250
217251 static GrpcEndpointSettings parse (Properties properties ) {
@@ -220,6 +254,10 @@ static GrpcEndpointSettings parse(Properties properties) {
220254 String clientKeyPath = properties .getValue (GRPC_TLS_KEY_PATH );
221255 String clientCertPath = properties .getValue (GRPC_TLS_CERT_PATH );
222256 String caCertPath = properties .getValue (GRPC_TLS_CA_PATH );
257+ boolean enablekeepAlive = properties .getValue (GRPC_ENABLE_KEEP_ALIVE );
258+ Duration keepAliveTimeSeconds = properties .getValue (GRPC_KEEP_ALIVE_TIME_SECONDS );
259+ Duration keepAliveTimeoutSeconds = properties .getValue (GRPC_KEEP_ALIVE_TIMEOUT_SECONDS );
260+ boolean keepAliveWithoutCalls = properties .getValue (GRPC_KEEP_ALIVE_WITHOUT_CALLS );
223261
224262 boolean secure = false ;
225263 String grpcEndpoint = properties .getValue (GRPC_ENDPOINT );
@@ -257,30 +295,33 @@ static GrpcEndpointSettings parse(Properties properties) {
257295 var authorityEndpoint = matcher .group ("authorityEndpoint" );
258296 if (authorityEndpoint != null ) {
259297 return new GrpcEndpointSettings (
260- String .format (
261- "dns://%s/%s:%d" ,
262- authorityEndpoint ,
263- address ,
264- port
265- ), secure , clientKeyPath , clientCertPath , caCertPath );
298+ String .format (
299+ "dns://%s/%s:%d" ,
300+ authorityEndpoint ,
301+ address ,
302+ port ),
303+ secure , clientKeyPath , clientCertPath , caCertPath , enablekeepAlive , keepAliveTimeSeconds ,
304+ keepAliveTimeoutSeconds , keepAliveWithoutCalls );
266305 }
267306
268307 var socket = matcher .group ("socket" );
269308 if (socket != null ) {
270- return new GrpcEndpointSettings (socket , secure , clientKeyPath , clientCertPath , caCertPath );
309+ return new GrpcEndpointSettings (socket , secure , clientKeyPath , clientCertPath , caCertPath , enablekeepAlive ,
310+ keepAliveTimeSeconds , keepAliveTimeoutSeconds , keepAliveWithoutCalls );
271311 }
272312
273313 var vsocket = matcher .group ("vsocket" );
274314 if (vsocket != null ) {
275- return new GrpcEndpointSettings (vsocket , secure , clientKeyPath , clientCertPath , caCertPath );
315+ return new GrpcEndpointSettings (vsocket , secure , clientKeyPath , clientCertPath , caCertPath , enablekeepAlive ,
316+ keepAliveTimeSeconds , keepAliveTimeoutSeconds , keepAliveWithoutCalls );
276317 }
277318 }
278319
279320 return new GrpcEndpointSettings (String .format (
280- "dns:///%s:%d" ,
281- address ,
282- port
283- ), secure , clientKeyPath , clientCertPath , caCertPath );
321+ "dns:///%s:%d" ,
322+ address ,
323+ port ), secure , clientKeyPath , clientCertPath , caCertPath , enablekeepAlive , keepAliveTimeSeconds ,
324+ keepAliveTimeoutSeconds , keepAliveWithoutCalls );
284325 }
285326
286327 }
0 commit comments