|
18 | 18 |
|
19 | 19 | import com.alibaba.fluss.annotation.Internal; |
20 | 20 | import com.alibaba.fluss.annotation.VisibleForTesting; |
| 21 | +import com.alibaba.fluss.exception.AuthorizationException; |
21 | 22 | import com.alibaba.fluss.exception.OutOfOrderSequenceException; |
22 | 23 | import com.alibaba.fluss.exception.UnknownWriterIdException; |
23 | 24 | import com.alibaba.fluss.metadata.PhysicalTablePath; |
|
27 | 28 | import com.alibaba.fluss.rpc.gateway.TabletServerGateway; |
28 | 29 | import com.alibaba.fluss.rpc.messages.InitWriterRequest; |
29 | 30 | import com.alibaba.fluss.rpc.protocol.Errors; |
| 31 | +import com.alibaba.fluss.utils.ExceptionUtils; |
30 | 32 |
|
31 | 33 | import org.slf4j.Logger; |
32 | 34 | import org.slf4j.LoggerFactory; |
|
35 | 37 |
|
36 | 38 | import java.util.Optional; |
37 | 39 | import java.util.Set; |
38 | | -import java.util.concurrent.ExecutionException; |
39 | 40 | import java.util.stream.Collectors; |
40 | 41 |
|
41 | 42 | import static com.alibaba.fluss.record.LogRecordBatch.NO_WRITER_ID; |
|
53 | 54 | public class IdempotenceManager { |
54 | 55 | private static final Logger LOG = LoggerFactory.getLogger(IdempotenceManager.class); |
55 | 56 |
|
| 57 | + // retry config for requesting writerId, maybe make it as configurable |
| 58 | + private static final int RETRY_TIMES = 3; |
| 59 | + private static final int RETRY_INTERVAL_MS = 100; |
| 60 | + |
56 | 61 | private final boolean idempotenceEnabled; |
57 | 62 | private final IdempotenceBucketMap idempotenceBucketMap; |
58 | 63 | private final int maxInflightRequestsPerBucket; |
@@ -283,13 +288,33 @@ synchronized boolean canRetry(WriteBatch batch, TableBucket tableBucket, Errors |
283 | 288 | return false; |
284 | 289 | } |
285 | 290 |
|
286 | | - void maybeWaitForWriterId(Set<PhysicalTablePath> tablePaths) |
287 | | - throws ExecutionException, InterruptedException { |
288 | | - if (!isWriterIdValid()) { |
289 | | - tabletServerGateway |
290 | | - .initWriter(prepareInitWriterRequest(tablePaths)) |
291 | | - .thenAccept(response -> setWriterId(response.getWriterId())) |
292 | | - .get(); // TODO: can optimize into async response handling. |
| 291 | + void maybeWaitForWriterId(Set<PhysicalTablePath> tablePaths) throws Throwable { |
| 292 | + if (isWriterIdValid()) { |
| 293 | + return; |
| 294 | + } |
| 295 | + |
| 296 | + int retryCount = 0; |
| 297 | + while (true) { |
| 298 | + try { |
| 299 | + tabletServerGateway |
| 300 | + .initWriter(prepareInitWriterRequest(tablePaths)) |
| 301 | + .thenAccept(response -> setWriterId(response.getWriterId())) |
| 302 | + .get(); // TODO: can optimize into async response handling. |
| 303 | + return; |
| 304 | + } catch (Exception e) { |
| 305 | + Throwable t = ExceptionUtils.stripExecutionException(e); |
| 306 | + if (t instanceof AuthorizationException || retryCount >= RETRY_TIMES) { |
| 307 | + throw t; |
| 308 | + } else { |
| 309 | + LOG.warn( |
| 310 | + "Failed to init writer id, the retry count: {}, error message: {}", |
| 311 | + retryCount, |
| 312 | + t.getMessage()); |
| 313 | + retryCount++; |
| 314 | + long delayMs = (long) (RETRY_INTERVAL_MS * Math.pow(2, retryCount)); |
| 315 | + Thread.sleep(delayMs); |
| 316 | + } |
| 317 | + } |
293 | 318 | } |
294 | 319 | } |
295 | 320 |
|
|
0 commit comments