shashank created CAMEL-25545:
--------------------------------
Summary: camel-pgevent - the consumer reconnects only after the
first lost connection; after the next one it stays disconnected without an
error while the route keeps running
Key: CAMEL-25545
URL: https://issues.apache.org/jira/browse/CAMEL-25545
Project: Camel
Issue Type: Bug
Components: camel-pgevent
Reporter: shashank
Assignee: shashank
{{PgEventConsumer.doInit}} (line 72 at main 9432ba16d026) creates one
{{BackgroundTask}} for reconnecting, and {{PgEventListener.reconnect()}} (line
103), which the driver calls through {{closed()}} when the connection is lost,
runs that same task every time:
{code:java}
if (!reconnectTask.isRunning()) {
reconnectTask.run(endpoint.getCamelContext(), () -> {
...
initConnection(); // new connection, LISTEN, notification listener
...
return true;
});
}
{code}
A {{BackgroundTask}} completes only once. Its latch ({{new CountDownLatch(1)}})
is counted down by the first successful attempt; after that {{run()}} schedules
an attempt with the initial delay of one second, {{waitForTaskCompletion}}
returns at once because the latch is already 0 and cancels the attempt, and
{{runTaskWrapper}} would do nothing anyway ("the task is done and every further
run is a no-op"). The other users of the task API (camel-master, camel-sjms,
camel-kafka) build a new task for each use.
So the consumer reconnects after the first connection loss, and after the
second one {{reconnect()}} returns without connecting: the consumer no longer
listens to the channel, no notification is routed any more, nothing is logged
after the "Connection to PostgreSQL lost unexpected. Re-connecting..." warning,
and the route still shows as started. Only a restart of the route (which runs
{{doInit}} again) repairs it. A database that restarts or fails over twice
during the lifetime of the route is enough.
h3. Reproduction
New {{PgEventConsumerReconnectTest}} (no database: a mocked {{DataSource}}
hands out mocked {{PGConnection}}s through the {{datasource}} option; the test
calls {{closed()}} on the listener as the driver does, and the call returns
when the reconnect is done). On main, twice:
{noformat}
PgEventConsumerReconnectTest.reconnectsAfterEveryConnectionLoss: The consumer
must reconnect after the second connection loss ==> expected: <3> but was: <2>
{noformat}
h3. Proposed fix
{{reconnect()}} creates a new {{BackgroundTask}} (same pool, name and budget as
before) for each reconnect, and keeps it in the (now volatile) field for the
"already running" check. With the fix the test also verifies that the third
connection executed {{LISTEN testchannel}} and got the notification listener.
No upgrade guide note: nothing changes for a consumer that has not lost its
connection twice. camel-pgevent with the fix: 1 unit test (the new one; the
module had none), 0 failures; the integration tests need a PostgreSQL container
(Docker) and were not run. Test dependency added: mockito-junit-jupiter.
Not changed here: a consumer that is stopped while a reconnect is waiting
leaves the thread that called {{closed()}} waiting on the task (the pool is
shut down, the task is not cancelled); that needs its own look.
Found by reading how the task API is used across components, with a small TLA+
model of the reconnect (connection lost, attempt, return of {{run()}}, the
latch of the task): "when reconnect() has returned the consumer listens to the
channel" holds for one connection loss and is violated for two (6 states); with
a new task per reconnect it holds for two and three losses. Confirmed with the
real consumer.
Affected: main, camel-4.22.x, camel-4.18.x, camel-4.14.x (same reconnect code
and the same single-use latch in {{BackgroundTask}}, GitHub contents API).
Duplicate check (2026-10-11): JIRA text "pgevent" since 2021 (10: CAMEL-22146
added the reconnect, CAMEL-22949 and CAMEL-23646 changed the task callback,
none about a second connection loss); GitHub open pull requests for
camel-pgevent: none. No open pull request changes {{PgEventConsumer}}.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)