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)

Reply via email to