shashank created CAMEL-25289:
--------------------------------
Summary: camel-iggy - after 8 failed sends or polls the producer
and the consumer wait forever for a pooled client; stopped producers and
consumers leak their connections; autoCommit=false fails without startingOffset
Key: CAMEL-25289
URL: https://issues.apache.org/jira/browse/CAMEL-25289
Project: Camel
Issue Type: Bug
Reporter: shashank
h3. 1. A failed request keeps its pooled client for good
{{IggyProducer.process}} and {{IggyFetchRecords.pollMessages}} borrow an
{{IggyBaseClient}} from their {{IggyClientConnectionPool}} and give it back
only after a successful request:
{code:java}
IggyBaseClient client = iggyClientConnectionPool.borrowObject();
...
client.messages().sendMessages(...); // throws: the client is never returned
iggyClientConnectionPool.returnClient(client);
{code}
Each failed send or poll (server restart, network error, missing topic) keeps
one client borrowed. The pool is a {{GenericObjectPool}} with the commons-pool2
defaults: at most 8 clients and {{borrowObject}} waits forever when they are
all borrowed. So after 8 failures:
* every later send waits forever in {{borrowObject}} (the calling route threads
hang), also after the Iggy server is back;
* the consumer thread waits forever and the consumer consumes nothing more,
while the route stays started.
Before that the consumer also polls again at once after a failure, in a tight
loop.
h3. 2. Stopped producers and consumers leak their connections
Neither the producer nor the consumer closes its pool when it stops, and
{{IggyClientFactory}} does not override {{destroyObject}}, so the (TCP or HTTP,
{{Closeable}}) clients are never closed. Every stop of a route or producer
leaks its connections and their threads.
h3. 3. autoCommit=false without startingOffset
{{startingOffset}} is documented with the default {{0}}
({{@UriParam(defaultValue = "0")}}), but the field is {{null}}. With
{{autoCommit=false}} and no {{startingOffset}} the consumer polls with
{{PollingStrategy.offset(null)}} and fails with a {{NullPointerException}} at
{{offset.add(...)}} on every poll.
h3. Reproduction
{{IggyMockClientTest}} (new, no Iggy server: the client factory is replaced
with Mockito {{mockConstruction}}, the pool is the real {{GenericObjectPool}}):
* {{testFailedSendsDoNotExhaustThePool}}: 10 sends that fail. On main the 9th
send never returns: {{execution timed out after 30000 ms}}.
* {{testProducerStopClosesTheClients}}: on main the client is never closed:
{{expected: <1> but was: <0>}}.
* {{testFailedPollDiscardsTheClient}}: on main the client of the failed poll is
not closed before the next poll: {{expected: <1> but was: <0>}}.
* {{testManualCommitStartsAtOffsetZeroByDefault}}: on main {{expected:
<PollingStrategy[kind=Offset, value=0]> but was: <PollingStrategy[kind=Offset,
value=null]>}}.
h3. Proposed fix
* The client of a failed request is invalidated (removed from the pool and
closed, it may be broken); a successful one is returned. The initialization at
start returns its client in a {{finally}}.
* The consumer waits one second after a failed poll (the same delay as when it
is suspended).
* {{IggyClientFactory.destroyObject}} closes the client; producers and
consumers close their pool when they stop.
* {{startingOffset}} defaults to {{0}}, as documented.
With the fix the 4 tests pass, and the module suite passes (13 unit tests; the
ITs need Docker). Note: an idle consumer still polls in a loop without delay
when the topic is empty (not changed here).
Affected: 4.18.x and main (the component is not on 4.14.x).
Duplicate check (2026-10-03): JIRA text "iggy" (25 issues: CAMEL-22222, 22234,
22779, 23149, 23532, ...): none about the pool, the clients or the starting
offset. GitHub pull requests "iggy": only dependency upgrades and the header
filter change.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)