Skip to content

Keep unsent messages when the session is reset by its schedule - #1345

Open
aymenjam wants to merge 3 commits into
quickfix-j:masterfrom
aymenjam:bug/hold-messages-outside-session-time-463-986
Open

aymenjam wants to merge 3 commits into
quickfix-j:masterfrom
aymenjam:bug/hold-messages-outside-session-time-463-986

Conversation

@aymenjam

Copy link
Copy Markdown
Contributor

Problem

When the app sends a message while the session is not logged on (for example outside the session time), the message is saved in the message store. Then the session is reset by its schedule, and the reset deletes the store. So the message is never sent.

This does not match the Javadoc of Application.onCreate(): "If no one is logged on, the messages will be sent at the time a connection is established with the counterparty."

Closes #986
Refs #463

Solution

This PR adds a new session setting: KeepUnsentMessagesOnReset (default N).

With KeepUnsentMessagesOnReset=Y:

  • When a message is saved but not sent, the store keeps the sequence number of the first unsent message.
  • When the session is reset by its schedule, the unsent application messages are copied into the new store, with new sequence numbers.
  • After the next logon, they are sent again with PossDupFlag=Y when the counterparty asks for them (ResendRequest).
  • The value is cleared after a successful logon.

The value is saved in the store, so it works after a restart.

As discussed in #986:

  • MessageStore has two new default methods: getFirstUnsentSenderMsgSeqNum() and setFirstUnsentSenderMsgSeqNum(int). By default they do nothing (get returns -1), so custom stores still compile and work as before.
  • The value is saved in a separate file or table:
    • MemoryStore: in memory.
    • FileStore and CachedFileStore: new file <session>.firstunsentseqnum.
    • JdbcStore: new table unsent_seqnums. The name can be changed with JdbcStoreUnsentSeqNumsTableName. The table is optional. Without it, JdbcStore works as before.
  • The SQL scripts for HSQLDB, MySQL, MSSQL, Oracle and PostgreSQL create the new table.

If the store does not support it, or if PersistMessages=N, the session logs a warning and works as before.

Messages are still lost with ResetOnLogon, ResetOnLogout, ResetOnDisconnect, a Logon with ResetSeqNumFlag=Y, or a call to Session.reset(). These resets are asked by the user or by the counterparty, so this PR does not change them.

Open question

The default is N, so nothing changes for current users. In #986 we did not decide if it should be Y by default. I am happy to change it.

Tests

  • SessionTest: unsent messages are kept after a scheduled reset, resent after logon, and kept after a restart; messages that were already sent are not kept; no change when the setting is off.
  • DefaultSessionFactoryTest: the new setting is read.
  • AbstractMessageStoreTest: get, set, refresh and reset of the new value. It runs for MemoryStore, FileStore, CachedFileStore and JdbcStore (also the legacy table layout).
  • JdbcStoreTest: JdbcStore works without the new table.

Before this change, some messages were lost. This happened when the
app sent a message while the session was not logged on, for example
outside the session time. The message was saved in the store, and then
the scheduled reset deleted it.

With KeepUnsentMessagesOnReset=Y, the message store keeps the sequence
number of the first message that was not sent. When the session is
reset by its schedule, the unsent application messages are copied to
the new store with new sequence numbers. After the next logon, they
are sent again when the counterparty asks for them.

The value is saved in the store, so it works after a restart. It is
supported by MemoryStore, FileStore and CachedFileStore.

The default is N. So the reset works the same as before.

Refs quickfix-j#463, quickfix-j#986
JdbcStore can now keep the first unsent sequence number. The value is
saved in a new table, "unsent_seqnums". The name can be changed with
JdbcStoreUnsentSeqNumsTableName.

The table is optional. Without it, JdbcStore works as before and
KeepUnsentMessagesOnReset has no effect.

The SQL scripts for HSQLDB, MySQL, MSSQL, Oracle and PostgreSQL create
the new table.

Refs quickfix-j#463, quickfix-j#986
@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.71975% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.20%. Comparing base (149869e) to head (d7444bf).

Files with missing lines Patch % Lines
quickfixj-core/src/main/java/quickfix/Session.java 86.56% 6 Missing and 3 partials ⚠️
...ickfixj-core/src/main/java/quickfix/JdbcStore.java 96.07% 2 Missing ⚠️
...uickfixj-core/src/main/java/quickfix/JdbcUtil.java 80.00% 0 Missing and 1 partial ⚠️
...fixj-core/src/main/java/quickfix/MessageStore.java 50.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1345      +/-   ##
============================================
+ Coverage     70.79%   71.20%   +0.41%     
- Complexity     2270     2324      +54     
============================================
  Files           161      162       +1     
  Lines          9077     9231     +154     
  Branches       1192     1213      +21     
============================================
+ Hits           6426     6573     +147     
- Misses         2198     2204       +6     
- Partials        453      454       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Add tests for several unsent messages, a scheduled reset without unsent
messages, the warnings when the setting has no effect, and the update
and custom table name in JdbcStore.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Messages are dropped when sent after EndTime or before StartTime

1 participant