1616
1717package  io .grpc .okhttp ;
1818
19+ import  static  io .grpc .okhttp .OkHttpServerBuilder .MAX_CONNECTION_AGE_NANOS_DISABLED ;
1920import  static  io .grpc .okhttp .OkHttpServerBuilder .MAX_CONNECTION_IDLE_NANOS_DISABLED ;
2021
2122import  com .google .common .base .Preconditions ;
3132import  io .grpc .internal .GrpcUtil ;
3233import  io .grpc .internal .KeepAliveEnforcer ;
3334import  io .grpc .internal .KeepAliveManager ;
35+ import  io .grpc .internal .LogExceptionRunnable ;
3436import  io .grpc .internal .MaxConnectionIdleManager ;
3537import  io .grpc .internal .ObjectPool ;
3638import  io .grpc .internal .SerializingExecutor ;
@@ -96,6 +98,7 @@ final class OkHttpServerTransport implements ServerTransport,
9698  private  Attributes  attributes ;
9799  private  KeepAliveManager  keepAliveManager ;
98100  private  MaxConnectionIdleManager  maxConnectionIdleManager ;
101+   private  ScheduledFuture <?> maxConnectionAgeMonitor ;
99102  private  final  KeepAliveEnforcer  keepAliveEnforcer ;
100103
101104  private  final  Object  lock  = new  Object ();
@@ -223,6 +226,15 @@ public void data(boolean outFinished, int streamId, Buffer source, int byteCount
223226        maxConnectionIdleManager .start (this ::shutdown , scheduledExecutorService );
224227      }
225228
229+       if  (config .maxConnectionAgeInNanos  != MAX_CONNECTION_AGE_NANOS_DISABLED ) {
230+         long  maxConnectionAgeInNanos  =
231+             (long ) ((.9D  + Math .random () * .2D ) * config .maxConnectionAgeInNanos );
232+         maxConnectionAgeMonitor  = scheduledExecutorService .schedule (
233+             new  LogExceptionRunnable (() -> shutdown (config .maxConnectionAgeGraceInNanos )),
234+             maxConnectionAgeInNanos ,
235+             TimeUnit .NANOSECONDS );
236+       }
237+ 
226238      transportExecutor .execute (
227239          new  FrameHandler (variant .newReader (Okio .buffer (Okio .source (socket )), false )));
228240    } catch  (Error  | IOException  | RuntimeException  ex ) {
@@ -238,6 +250,10 @@ public void data(boolean outFinished, int streamId, Buffer source, int byteCount
238250
239251  @ Override 
240252  public  void  shutdown () {
253+     shutdown (TimeUnit .SECONDS .toNanos (1L ));
254+   }
255+ 
256+   private  void  shutdown (Long  graceTimeInNanos ) {
241257    synchronized  (lock ) {
242258      if  (gracefulShutdown  || abruptShutdown ) {
243259        return ;
@@ -251,7 +267,7 @@ public void shutdown() {
251267        // we also set a timer to limit the upper bound in case the PING is excessively stalled or 
252268        // the client is malicious. 
253269        secondGoawayTimer  = scheduledExecutorService .schedule (
254-             this ::triggerGracefulSecondGoaway , 1 , TimeUnit .SECONDS );
270+             this ::triggerGracefulSecondGoaway , graceTimeInNanos , TimeUnit .NANOSECONDS );
255271        frameWriter .goAway (Integer .MAX_VALUE , ErrorCode .NO_ERROR , new  byte [0 ]);
256272        frameWriter .ping (false , 0 , GRACEFUL_SHUTDOWN_PING );
257273        frameWriter .flush ();
@@ -348,6 +364,10 @@ private void terminated() {
348364    if  (maxConnectionIdleManager  != null ) {
349365      maxConnectionIdleManager .onTransportTermination ();
350366    }
367+ 
368+     if  (maxConnectionAgeMonitor  != null ) {
369+       maxConnectionAgeMonitor .cancel (false );
370+     }
351371    transportExecutor  = config .transportExecutorPool .returnObject (transportExecutor );
352372    scheduledExecutorService  =
353373        config .scheduledExecutorServicePool .returnObject (scheduledExecutorService );
@@ -479,6 +499,8 @@ static final class Config {
479499    final  long  maxConnectionIdleNanos ;
480500    final  boolean  permitKeepAliveWithoutCalls ;
481501    final  long  permitKeepAliveTimeInNanos ;
502+     final  long  maxConnectionAgeInNanos ;
503+     final  long  maxConnectionAgeGraceInNanos ;
482504
483505    public  Config (
484506        OkHttpServerBuilder  builder ,
@@ -501,6 +523,8 @@ public Config(
501523      maxConnectionIdleNanos  = builder .maxConnectionIdleInNanos ;
502524      permitKeepAliveWithoutCalls  = builder .permitKeepAliveWithoutCalls ;
503525      permitKeepAliveTimeInNanos  = builder .permitKeepAliveTimeInNanos ;
526+       maxConnectionAgeInNanos  = builder .maxConnectionAgeInNanos ;
527+       maxConnectionAgeGraceInNanos  = builder .maxConnectionAgeGraceInNanos ;
504528    }
505529  }
506530
0 commit comments