|
46 | 46 | */
|
47 | 47 | public class MessageProcessorRunnable implements Runnable {
|
48 | 48 | private static final Logger logger = LogManager.getLogger(MessageProcessorRunnable.class);
|
| 49 | + private static final String ID = "_id"; |
| 50 | + private static final String OP_TYPE = "_op_type"; |
| 51 | + private static final String SOURCE = "_source"; |
| 52 | + private static final int WAIT_BEFORE_RETRY_DURATION_MS = 5000; |
49 | 53 |
|
| 54 | + private volatile IngestionErrorStrategy errorStrategy; |
50 | 55 | private final BlockingQueue<IngestionShardConsumer.ReadResult<? extends IngestionShardPointer, ? extends Message>> blockingQueue;
|
51 | 56 | private final MessageProcessor messageProcessor;
|
52 | 57 | private final CounterMetric stats = new CounterMetric();
|
53 |
| - private IngestionErrorStrategy errorStrategy; |
54 |
| - |
55 |
| - private static final String ID = "_id"; |
56 |
| - private static final String OP_TYPE = "_op_type"; |
57 |
| - private static final String SOURCE = "_source"; |
58 | 58 |
|
59 | 59 | /**
|
60 | 60 | * Constructor.
|
@@ -223,32 +223,59 @@ private static BytesReference convertToBytes(Object object) throws IOException {
|
223 | 223 | return blockingQueue;
|
224 | 224 | }
|
225 | 225 |
|
| 226 | + /** |
| 227 | + * Polls messages from the blocking queue and processes messages. If message processing fails, the failed message |
| 228 | + * is retried indefinitely after a retry wait time, unless a DROP error policy is used to skip the failed message. |
| 229 | + */ |
226 | 230 | @Override
|
227 | 231 | public void run() {
|
| 232 | + IngestionShardConsumer.ReadResult<? extends IngestionShardPointer, ? extends Message> readResult = null; |
| 233 | + |
228 | 234 | while (!(Thread.currentThread().isInterrupted())) {
|
229 |
| - IngestionShardConsumer.ReadResult<? extends IngestionShardPointer, ? extends Message> result = null; |
230 | 235 | try {
|
231 |
| - result = blockingQueue.poll(1000, TimeUnit.MILLISECONDS); |
| 236 | + if (readResult == null) { |
| 237 | + readResult = blockingQueue.poll(1000, TimeUnit.MILLISECONDS); |
| 238 | + } |
232 | 239 | } catch (InterruptedException e) {
|
233 | 240 | // TODO: add metric
|
234 | 241 | logger.debug("MessageProcessorRunnable poll interruptedException", e);
|
235 | 242 | Thread.currentThread().interrupt(); // Restore interrupt status
|
236 | 243 | }
|
237 |
| - if (result != null) { |
| 244 | + if (readResult != null) { |
238 | 245 | try {
|
239 | 246 | stats.inc();
|
240 |
| - messageProcessor.process(result.getMessage(), result.getPointer()); |
| 247 | + messageProcessor.process(readResult.getMessage(), readResult.getPointer()); |
| 248 | + readResult = null; |
241 | 249 | } catch (Exception e) {
|
242 | 250 | errorStrategy.handleError(e, IngestionErrorStrategy.ErrorStage.PROCESSING);
|
243 |
| - if (errorStrategy.shouldPauseIngestion(e, IngestionErrorStrategy.ErrorStage.PROCESSING)) { |
244 |
| - Thread.currentThread().interrupt(); |
| 251 | + if (errorStrategy.shouldIgnoreError(e, IngestionErrorStrategy.ErrorStage.PROCESSING)) { |
| 252 | + readResult = null; |
| 253 | + } else { |
| 254 | + waitBeforeRetry(); |
245 | 255 | }
|
246 | 256 | }
|
247 | 257 | }
|
248 | 258 | }
|
249 | 259 | }
|
250 | 260 |
|
| 261 | + private void waitBeforeRetry() { |
| 262 | + try { |
| 263 | + Thread.sleep(WAIT_BEFORE_RETRY_DURATION_MS); |
| 264 | + } catch (InterruptedException e) { |
| 265 | + logger.debug("MessageProcessor thread interrupted while waiting for retry", e); |
| 266 | + Thread.currentThread().interrupt(); // Restore interrupt status |
| 267 | + } |
| 268 | + } |
| 269 | + |
251 | 270 | public CounterMetric getStats() {
|
252 | 271 | return stats;
|
253 | 272 | }
|
| 273 | + |
| 274 | + public IngestionErrorStrategy getErrorStrategy() { |
| 275 | + return this.errorStrategy; |
| 276 | + } |
| 277 | + |
| 278 | + public void setErrorStrategy(IngestionErrorStrategy errorStrategy) { |
| 279 | + this.errorStrategy = errorStrategy; |
| 280 | + } |
254 | 281 | }
|
0 commit comments