if (processMethod.needsInput()) {
flowletContext.getProgramMetrics().gauge("process.tuples.attempt.read", 1);
}
// Begin transaction and dequeue
final TransactionContext txContext = flowletContext.createTransactionContext();
try {
txContext.start();
try {
InputDatum<T> input = entry.getProcessSpec().getQueueReader().dequeue(0, TimeUnit.MILLISECONDS);
if (!input.needProcess()) {
entry.backOff();
// End the transaction if nothing in the queue
txContext.finish();
return false;
}
// Resetting back-off time to minimum back-off time,
// since an entry to process was de-queued and most likely more entries will follow.
entry.resetBackOff();
if (!entry.isRetry()) {
// Only increment the inflight count for non-retry entries.
// The inflight would get decrement when the transaction committed successfully or input get ignored.
// See the processMethodCallback function.
inflight.getAndIncrement();
}
try {
// Call the process method and commit the transaction. The current process entry will put
// back to queue in the postProcess method (either a retry copy or itself).
ProcessMethod.ProcessResult<?> result = processMethod.invoke(input);
postProcess(processMethodCallback(processQueue, entry, input), txContext, input, result);
return true;
} catch (Throwable t) {
// If exception thrown from invoke or postProcess, the inflight count would not be touched.
// hence need to decrements here
if (!entry.isRetry()) {
inflight.decrementAndGet();
}
}
} catch (Throwable t) {
LOG.error("System failure: {}", flowletContext, t);
try {
txContext.abort();
} catch (Throwable e) {
LOG.error("Fail to abort transaction: {}", flowletContext, e);
}
}
} catch (Throwable t) {