shashank created CAMEL-25511:
--------------------------------
Summary: camel-jooq - the consumer deletes an entity whose
exchange failed (consumeDelete=true, the default), so the row is lost
Key: CAMEL-25511
URL: https://issues.apache.org/jira/browse/CAMEL-25511
Project: Camel
Issue Type: Bug
Components: camel-jooq
Reporter: shashank
With {{consumeDelete=true}} (the default) {{JooqConsumer.poll()}} (lines 53-81
at main c578a42a776d) fetches all the entities of the table, hands them to
{{processBatch}} and then runs {{context.batchDelete(results).execute()}} on
*all* fetched entities, whatever happened to their exchanges:
{code:java}
int messagePolled = processBatch(CastUtils.cast(answer));
if (configuration.isConsumeDelete()) {
context.batchDelete(results).execute();
}
{code}
A failed route does not throw out of {{getProcessor().process(exchange)}}; the
error handler leaves the exception on the exchange. So a row whose processing
failed (or whose exchange was marked rollback only) is deleted and lost,
although the docs present the table as "a logical queue" and say the entity is
deleted "when it has been processed". When a graceful shutdown starts after the
entities were fetched, {{isBatchAllowed()}} is false and {{processBatch}}
processes none of them, but they are all deleted too.
The consumers of the other "database as a queue" components do not do this:
camel-jpa deletes an entity only when its exchange has no exception (otherwise
the transaction is rolled back), and camel-sql runs {{onConsume}} only for a
successful exchange ({{onConsumeFailed}} otherwise).
h3. Reproduction
New {{JooqConsumerDeleteFailedTest}} (HSQLDB as in the other tests; the route
uses {{startScheduler=false}} and the test calls {{poll()}} once, so it is
deterministic). Two authors are inserted; the route throws for one of them, or
marks its exchange rollback only, or the poll runs after
{{deferShutdown(CompleteCurrentTaskOnly)}} as the shutdown strategy calls it.
On main all three tests fail:
{noformat}
testFailedExchangeKeepsRow: only the successfully processed author must be
deleted ==> expected: <[2]> but was: <[]>
testRollbackOnlyExchangeKeepsRow: an author whose exchange was marked rollback
only must not be deleted ==> expected: <[2]> but was: <[]>
testNotProcessedEntitiesKeepRows: entities that were not processed must not be
deleted ==> expected: <2> but was: <0>
{noformat}
h3. Proposed fix
{{processBatch}} records, right after processing each exchange, whether it
completed successfully (not failed, not rollback only); {{poll}} deletes only
those entities. A failed entity stays in the table and is consumed again by the
next poll (an entity that always fails is processed at every poll, as with
camel-jpa). Docs (and the catalog copy) say so, and the 4.23 upgrade guide has
a note: a route that relied on failing entities being deleted now receives them
again and can use {{onException(...).handled(true)}}. camel-jooq tests with the
fix: 16, 0 failures.
Found with a Lean 4 model of the poll (fetched entities with the outcome of
their exchange: ok, failed, not processed): "an entity is deleted only if its
exchange succeeded" fails for one failed entity, main is proved to delete every
fetched entity and to agree with the property exactly when all exchanges
succeeded; the fix is proved to satisfy it and to delete the same entities as
main when all exchanges succeed. Confirmed with the real consumer.
Affected: main, camel-4.22.x, camel-4.18.x, camel-4.14.x (same code, GitHub
contents API; latest releases 4.22.1, 4.18.4, 4.14.9). The consumer has deleted
all fetched entities since it was added (CAMEL-13256, Camel 3.0).
Duplicate check (2026-10-09, repeated in review): JIRA text "jooq" (23, none
about deletion or failures; CAMEL-13261 added the queue use case),
"consumeDelete" (13, all camel-jpa or the jooq queue feature); GitHub pull
requests "jooq consumer delete", "jooq consumeDelete", "JooqConsumer", "jooq
failed": none. No open pull request changes {{JooqConsumer}}.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)