papinifrancesco commented on issue #2630:
URL: https://github.com/apache/activemq/issues/2630#issuecomment-5959474384

   I have a fix for this and would like to check the approach with you before 
opening a PR. @cshannon, since this builds on AMQ-9698, your view would be 
especially useful.
   
   **Approach.** Implement `recoverExpired()` for the JDBC store, so `Topic` 
uses it for JDBC as well as KahaDB and no longer falls back to `doBrowse()`. 
Per eligible durable subscription, `JDBCTopicMessageStore.recoverExpired()` 
runs two plain-SQL queries:
   
   1. read the subscription's `LAST_ACKED_ID` and the id of the first pending 
message that is not expired (or is part of a prepared XA transaction);
   2. load the expired messages between those two ids, at most 
`maxExpirePageSize` of them (`setMaxRows`).
   
   Nothing in it is specific to PostgreSQL. A topic browse (JMX, 
`StatisticsBroker`) expires through the same path on JDBC.
   
   **A second bug, found while writing it.** The JDBC store records a durable 
subscription's acks as a high-water mark (`UPDATE ACTIVEMQ_ACKS SET 
LAST_ACKED_ID=?`), so acking an expired message also acks every earlier message 
of that subscription. Today, when a message with a TTL expires behind one 
without a TTL, the expiry task (or a browse) acks the expired one and the 
earlier message is lost:
   
   1. offline durable subscription, JDBC store;
   2. send A with no TTL, then B with a 500 ms TTL;
   3. wait for the expiry task: B is expired, `LAST_ACKED_ID` jumps to B's id;
   4. restart the broker and reconnect the subscription: A is never delivered.
   
   The same test passes on KahaDB, which tracks acks per message. That is why 
the fix stops at the first non-expired message: it only expires the run of 
expired messages directly after `LAST_ACKED_ID` (per priority with prioritized 
messages). The visible difference from KahaDB is that expired messages queued 
behind a non-expiring one stay in the store until that one is consumed; they 
are still dropped at dispatch. Would you like this filed as a separate issue?
   
   **Testing.**
   
   - New unit tests on Derby for both bugs:
     - `recoverExpired` itself: stopping at the first non-expired message, the 
page limit, priorities, a prepared XA transaction;
     - an end-to-end test with a broker restart, for both the expiry task and 
the browse path;
     - `JDBCPersistenceAdapterExpiredMessageTest` updated to the new method.
   - The existing JDBC, expiry and durable-subscription tests show no 
regressions.
   - On PostgreSQL, the reproduction repository now also runs patched legs: 
https://github.com/papinifrancesco/activemq-jdbc-topic-expiry-oom/actions/runs/37039551631.
 6.3.2 and 6.2.10 with the patch survive the 200,000-message backlog. With 30 s 
TTLs, the expiry task acks 400 messages per run with no out-of-memory error, 
while unpatched 6.3.2 with the same TTLs runs out of memory.
   
   **Left out:** a manual browse of a JDBC topic still reads the whole result 
set on PostgreSQL. Only an explicit JMX or statistics browse triggers it, never 
the periodic task, so I kept it out of this change.
   
   **Disclosure:** the patch, the tests and the reproduction were written with 
an AI assistant (Claude Code, Anthropic). The test results above come from the 
runs described there: the unit tests locally, the PostgreSQL cases in the 
linked CI run. In line with the ASF guidance on generative tooling, the commits 
will carry a `Co-authored-by` trailer naming the tool.
   
   If the approach is fine, I'll open a PR against `main`; the same change 
applies to 6.3.x, and on 6.2.x with a whitespace-only difference.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact


Reply via email to