shashank created CAMEL-25711:
--------------------------------
Summary: camel-mongodb-gridfs - the consumer stops polling for
good, without a log line and with the route still started, after one poll fails
(for example MongoDB not reachable for longer than the server selection timeout)
Key: CAMEL-25711
URL: https://issues.apache.org/jira/browse/CAMEL-25711
Project: Camel
Issue Type: Bug
Components: camel-mongodb-gridfs
Reporter: shashank
Assignee: shashank
{{GridFsConsumer}} polls with a {{BackgroundTask}} built
{{withUnlimitedDuration()}} ({{GridFsConsumer.run}}, main 18f53efde6c7
{{GridFsConsumer.java}} 124-139). Only {{getProcessor().process(exchange)}} is
inside a {{try}} in {{processCollection}}; the query of the bucket
({{getGridFSFileMongoCursor}}, 151), {{cursor.hasNext()}} / {{next()}}, the
{{findOneAndUpdate}} that marks a file {{processing}} for the file attribute
strategies (162), {{openDownloadStream}} (166) and the update of the persistent
timestamp (202) are not. When one of them throws, for example a
{{MongoTimeoutException}} because MongoDB cannot be reached for longer than the
server selection timeout (30 s by default) or a {{MongoSocketReadException}}
when the connection drops while the cursor reads, the exception leaves the
supplier. {{BackgroundTask.runTaskWrapper}} marks the task failed, releases
{{run()}} (CAMEL-24286) and rethrows on the scheduler thread, so
{{scheduleWithFixedDelay}} never runs the task again.
The consumer then stays started and routes nothing until the route is
restarted. Nothing is logged: the exception ends in the {{Future}} of the
scheduled task. This happens with every query strategy, with the default
options.
With {{queryStrategy=PersistentTimestamp}} or
{{PersistentTimestampAndFileAttribute}} there is a second path: {{run()}} reads
the persistent timestamp collection (105-119) on the consumer's executor thread
before it schedules the polls. If MongoDB cannot be reached when the route
starts, {{run()}} throws and no poll is ever scheduled.
h3. Reproduction
Two new tests in {{GridFsConsumerTimestampTest}} use the fake bucket of that
class (Mockito, no MongoDB):
* {{consumerKeepsPollingAfterAFailedPoll}}, once for each of the 5 query
strategies: the first 2 queries of the bucket throw {{MongoTimeoutException}},
then a file is stored. On main the consumer never polls again ({{the consumer
did not poll 3 times}}) and the file is never routed.
*
{{persistentTimestampStrategyKeepsPollingWhenTheTimestampCannotBeReadAtStart}}:
the first read of the timestamp collection throws. On main no poll runs.
On main all 6 cases fail; with the fix they pass.
h3. Proposed fix
The supplier of the task calls a new {{poll}} method that catches the
exception, reports the first failure of a run of failures through the
consumer's {{ExceptionHandler}} (WARN with the stack trace by default; the next
ones at DEBUG, as the polls run every {{delay}}, 500 ms by default; one INFO
line when a poll works again), and returns {{false}}. The next poll then tries
again after {{delay}}. {{camel-mongodb}} also catches the exception of a poll
and goes on in its consumer thread ({{MongoAbstractConsumerThread.java}}
103-110 on main, CAMEL-16025); it logs every failure at WARN with the stack
trace, this change reports only the first of a run of failures because the
polls repeat every {{delay}}. The persistent timestamp is read by the first
poll that can reach MongoDB instead of by {{run()}}, so a failure there is
retried in the same way. No option or default changes.
Not changed: a file claimed with the {{processing}} attribute (file attribute
strategies) before the poll fails still keeps that attribute, as before.
How it was found: CAMEL-24286 names this path in its description, but its fix
changed only {{BackgroundTask}}, and {{run()}} now returns while the poller
stays dead. The camel-mongodb consumer had the same "consumer thread ends on a
server outage" defect (CAMEL-25679). The tests confirmed it.
Affected: main (18f53efde6c7; tested). camel-4.23.x and camel-4.22.x poll with
the same {{BackgroundTask}} and have the same uncaught calls and the same
timestamp read in {{run()}} (read, not run). camel-4.18.x and camel-4.14.x have
the same uncaught calls, but {{run()}} polls with a {{ForegroundTask}} there:
the exception leaves {{run()}} and ends the consumer thread, with the same
result (only the default handler of the thread prints it on stderr) (read, not
run).
Duplicate check (2026-10-16): JIRA text "gridfs consumer", "GridFsConsumer",
"gridfs polling stops" (CAMEL-25607, CAMEL-24905, CAMEL-24272, CAMEL-24286,
CAMEL-23577, CAMEL-17121: CAMEL-24286 describes the path but fixed only
BackgroundTask; none about the consumer staying stopped); GitHub pull requests
"gridfs", "GridFsConsumer" (#27794, #26787, #25217, #25164: none about this).
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)