2020import static org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .base .Preconditions .checkNotNull ;
2121import static org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .base .Preconditions .checkState ;
2222
23- import com .google .auto .value .AutoValue ;
2423import java .io .PrintWriter ;
2524import java .time .Duration ;
2625import java .util .HashMap ;
@@ -77,6 +76,7 @@ private static class StreamAndRequest {
7776 private final JobHeader jobHeader ;
7877 private final int streamingRpcBatchLimit ;
7978 private volatile boolean logMissingResponse = true ;
79+ private final Duration maxRetryDuration ;
8080
8181 private GrpcCommitWorkStream (
8282 String backendWorkerToken ,
@@ -90,6 +90,7 @@ private GrpcCommitWorkStream(
9090 AtomicLong idGenerator ,
9191 int streamingRpcBatchLimit ,
9292 Duration halfClosePhysicalStreamAfter ,
93+ Duration maxRetryDuration ,
9394 ScheduledExecutorService executor ) {
9495 super (
9596 LOG ,
@@ -104,6 +105,7 @@ private GrpcCommitWorkStream(
104105 this .idGenerator = idGenerator ;
105106 this .jobHeader = jobHeader ;
106107 this .streamingRpcBatchLimit = streamingRpcBatchLimit ;
108+ this .maxRetryDuration = maxRetryDuration ;
107109 }
108110
109111 static GrpcCommitWorkStream create (
@@ -118,6 +120,7 @@ static GrpcCommitWorkStream create(
118120 AtomicLong idGenerator ,
119121 int streamingRpcBatchLimit ,
120122 Duration halfClosePhysicalStreamAfter ,
123+ Duration maxRetryDuration ,
121124 ScheduledExecutorService executor ) {
122125 return new GrpcCommitWorkStream (
123126 backendWorkerToken ,
@@ -130,6 +133,7 @@ static GrpcCommitWorkStream create(
130133 idGenerator ,
131134 streamingRpcBatchLimit ,
132135 halfClosePhysicalStreamAfter ,
136+ maxRetryDuration ,
133137 executor );
134138 }
135139
@@ -224,14 +228,50 @@ public void onResponse(StreamingCommitResponse response) {
224228 failureHandler .throwIfNonEmpty ();
225229 }
226230
227- @ Override
228231 @ SuppressWarnings ("ReferenceEquality" )
232+ private boolean belongsToThisHandler (StreamAndRequest streamAndRequest ) {
233+ return streamAndRequest .handler == this ;
234+ }
235+
236+ @ Override
229237 public boolean hasPendingRequests () {
230- return pending .entrySet ().stream ().anyMatch (e -> e .getValue (). handler == this );
238+ return pending .entrySet ().stream ().anyMatch (e -> belongsToThisHandler ( e .getValue ()) );
231239 }
232240
233241 @ Override
242+ @ SuppressWarnings ("ReferenceEquality" )
234243 public void onDone (Status status ) {
244+ if (maxRetryDuration .compareTo (Duration .ZERO ) > 0 ) {
245+ // Remove the requests that have exceeded the retry time so they are not retried.
246+ long startTimeRetryThresholdMsec = System .currentTimeMillis () - maxRetryDuration .toMillis ();
247+ Iterator <Map .Entry <Long , StreamAndRequest >> iterator = pending .entrySet ().iterator ();
248+ int keptRequests = 0 , removedRequests = 0 ;
249+ while (iterator .hasNext ()) {
250+ StreamAndRequest streamAndRequest = checkNotNull (iterator .next ().getValue ());
251+ PendingRequest pendingRequest = streamAndRequest .request ;
252+ if (!belongsToThisHandler (streamAndRequest )
253+ || pendingRequest .getStartTimeMillis () > startTimeRetryThresholdMsec ) {
254+ ++keptRequests ;
255+ continue ;
256+ }
257+ ++removedRequests ;
258+ try {
259+ pendingRequest .completeWithStatus (CommitStatus .ABORTED );
260+ } catch (RuntimeException e ) {
261+ // Catch possible exceptions to ensure that an exception for one commit does not prevent
262+ // other commits from being processed. Aggregate all the failures to throw after
263+ // processing the response if they exist.
264+ LOG .warn ("Exception while aborting commit due to retry timeout." , e );
265+ }
266+ iterator .remove ();
267+ }
268+ if (removedRequests > 0 ) {
269+ LOG .info (
270+ "Aborting {} commits which have exceeded retry deadline, kept {}. Work will be retried as needed by service." ,
271+ removedRequests ,
272+ keptRequests );
273+ }
274+ }
235275 if (status .isOk () && hasPendingRequests ()) {
236276 LOG .warn ("Unexpected requests without responses on drained physical stream, retrying." );
237277 }
@@ -270,7 +310,7 @@ private void flushInternal(Map<Long, PendingRequest> requests)
270310
271311 if (requests .size () == 1 ) {
272312 Map .Entry <Long , PendingRequest > elem = requests .entrySet ().iterator ().next ();
273- if (elem .getValue ().request ().getSerializedSize ()
313+ if (elem .getValue ().getRequest ().getSerializedSize ()
274314 > AbstractWindmillStream .RPC_STREAM_CHUNK_SIZE ) {
275315 issueMultiChunkRequest (elem .getKey (), elem .getValue ());
276316 } else {
@@ -286,7 +326,7 @@ private void issueSingleRequest(long id, PendingRequest pendingRequest)
286326 StreamingCommitWorkRequest .Builder requestBuilder = StreamingCommitWorkRequest .newBuilder ();
287327 requestBuilder
288328 .addCommitChunkBuilder ()
289- .setComputationId (pendingRequest .computationId ())
329+ .setComputationId (pendingRequest .getComputationId ())
290330 .setRequestId (id )
291331 .setShardingKey (pendingRequest .shardingKey ())
292332 .setSerializedWorkItemCommit (pendingRequest .serializedCommit ());
@@ -311,9 +351,9 @@ private void issueBatchedRequest(Map<Long, PendingRequest> requests)
311351 for (Map .Entry <Long , PendingRequest > entry : requests .entrySet ()) {
312352 PendingRequest request = entry .getValue ();
313353 StreamingCommitRequestChunk .Builder chunkBuilder = requestBuilder .addCommitChunkBuilder ();
314- if (lastComputation == null || !lastComputation .equals (request .computationId ())) {
315- chunkBuilder .setComputationId (request .computationId ());
316- lastComputation = request .computationId ();
354+ if (lastComputation == null || !lastComputation .equals (request .getComputationId ())) {
355+ chunkBuilder .setComputationId (request .getComputationId ());
356+ lastComputation = request .getComputationId ();
317357 }
318358 chunkBuilder
319359 .setRequestId (entry .getKey ())
@@ -338,7 +378,7 @@ private void issueBatchedRequest(Map<Long, PendingRequest> requests)
338378
339379 private void issueMultiChunkRequest (long id , PendingRequest pendingRequest )
340380 throws WindmillStreamShutdownException {
341- checkNotNull (pendingRequest .computationId (), "Cannot commit WorkItem w/o a computationId." );
381+ checkNotNull (pendingRequest .getComputationId (), "Cannot commit WorkItem w/o a computationId." );
342382 ByteString serializedCommit = pendingRequest .serializedCommit ();
343383 synchronized (this ) {
344384 if (isShutdown ) {
@@ -359,7 +399,7 @@ private void issueMultiChunkRequest(long id, PendingRequest pendingRequest)
359399 StreamingCommitRequestChunk .newBuilder ()
360400 .setRequestId (id )
361401 .setSerializedWorkItemCommit (chunk )
362- .setComputationId (pendingRequest .computationId ())
402+ .setComputationId (pendingRequest .getComputationId ())
363403 .setShardingKey (pendingRequest .shardingKey ());
364404 int remaining = serializedCommit .size () - end ;
365405 if (remaining > 0 ) {
@@ -376,34 +416,46 @@ private void issueMultiChunkRequest(long id, PendingRequest pendingRequest)
376416 }
377417 }
378418
379- @ AutoValue
380- abstract static class PendingRequest {
419+ private static class PendingRequest {
420+ private final String computationId ;
421+ private final WorkItemCommitRequest request ;
422+ private final Consumer <CommitStatus > onDone ;
423+ private final long startTimeMillis ;
381424
382- private static PendingRequest create (
425+ private PendingRequest (
383426 String computationId , WorkItemCommitRequest request , Consumer <CommitStatus > onDone ) {
384- return new AutoValue_GrpcCommitWorkStream_PendingRequest (computationId , request , onDone );
427+ this .computationId = computationId ;
428+ this .request = request ;
429+ this .onDone = onDone ;
430+ this .startTimeMillis = System .currentTimeMillis ();
385431 }
386432
387- abstract String computationId ();
433+ String getComputationId () {
434+ return computationId ;
435+ }
388436
389- abstract WorkItemCommitRequest request ();
437+ WorkItemCommitRequest getRequest () {
438+ return request ;
439+ }
390440
391- abstract Consumer <CommitStatus > onDone ();
441+ long getStartTimeMillis () {
442+ return startTimeMillis ;
443+ }
392444
393445 private long getBytes () {
394- return (long ) request () .getSerializedSize () + computationId () .length ();
446+ return (long ) request .getSerializedSize () + computationId .length ();
395447 }
396448
397449 private ByteString serializedCommit () {
398- return request () .toByteString ();
450+ return request .toByteString ();
399451 }
400452
401453 private void completeWithStatus (CommitStatus commitStatus ) {
402- onDone () .accept (commitStatus );
454+ onDone .accept (commitStatus );
403455 }
404456
405457 private long shardingKey () {
406- return request () .getShardingKey ();
458+ return request .getShardingKey ();
407459 }
408460
409461 private void abort () {
@@ -462,7 +514,7 @@ public boolean commitWorkItem(
462514 return false ;
463515 }
464516
465- PendingRequest request = PendingRequest . create (computation , commitRequest , onDone );
517+ PendingRequest request = new PendingRequest (computation , commitRequest , onDone );
466518 add (idGenerator .incrementAndGet (), request );
467519 return true ;
468520 }
0 commit comments