Skip to content

docs: Add QuickFIX/J threading model documentation#1171

Draft
Copilot wants to merge 6 commits intomasterfrom
copilot/add-threading-documentation-page
Draft

docs: Add QuickFIX/J threading model documentation#1171
Copilot wants to merge 6 commits intomasterfrom
copilot/add-threading-documentation-page

Conversation

Copy link
Contributor

Copilot AI commented Mar 21, 2026

Documents the QFJ threading model in detail — covering the two EventHandlingStrategy implementations, the always-present timer thread, their interaction, and thread-safety implications for application developers.

New files

  • docs/threading-model.md — Markdown version for GitHub rendering; covers all threading concepts with ASCII diagrams and code snippets from actual source
  • quickfixj-core/src/main/doc/usermanual/usage/threading.html — HTML version matching the existing usermanual style (application.html conventions: DOCTYPE, style.css, header/footer)

Updated

  • quickfixj-core/src/main/doc/usermanual/index.html — Added "Threading Model" link after "Creating Your Application"
  • README.md — Added ## threading model section linking to docs/threading-model.md

Topics covered

  • SingleThreadedEventHandlingStrategy (shared queue, single QFJ Message Processor daemon thread) vs ThreadPerSessionEventHandlingStrategy (per-session QF/J Session dispatcher: <sessionID> threads)
  • The QFJ Timer thread (SessionConnector.SessionTimerTask) fires every 1 s and calls Session.next() on all sessions — orthogonal to which strategy is in use
  • Distinction between Session.next() (timer: heartbeats, logon, schedule) and Session.next(Message) (dispatchers: message processing)
  • Queue capacity / watermark back-pressure options for both strategies
  • Custom Executor injection (setExecutor()) for virtual-thread or pool integration
  • Thread-safety contract: single-threaded connectors serialize callbacks; threaded connectors require a thread-safe Application implementation
Original prompt

Task

Add a new documentation page covering the QuickFIX/J threading model in detail. The documentation should be placed in quickfixj-core/src/main/doc/usermanual/usage/ as threading.html (following the existing HTML docs pattern) and also as a Markdown file docs/threading-model.md for GitHub rendering.


Content Requirements

The documentation must cover the following topics precisely, based on the actual source code:


1. Overview

QFJ uses Apache MINA for non-blocking I/O. The threading model is controlled by the EventHandlingStrategy interface, with two concrete implementations:

  • SingleThreadedEventHandlingStrategy — one thread for all sessions (SocketAcceptor, SocketInitiator)
  • ThreadPerSessionEventHandlingStrategy — one thread per session (ThreadedSocketAcceptor, ThreadedSocketInitiator)

Both are orthogonal to the timer thread, which is always present and always calls Session.next() on a 1-second schedule.


2. Connector classes and their strategy

Connector class Event handling strategy Thread name(s)
SocketAcceptor SingleThreadedEventHandlingStrategy QFJ Message Processor
SocketInitiator SingleThreadedEventHandlingStrategy QFJ Message Processor
ThreadedSocketAcceptor ThreadPerSessionEventHandlingStrategy QF/J Session dispatcher: <sessionID>
ThreadedSocketInitiator ThreadPerSessionEventHandlingStrategy QF/J Session dispatcher: <sessionID>

3. Single-threaded model (SingleThreadedEventHandlingStrategy)

Class: quickfix.mina.SingleThreadedEventHandlingStrategy
Source: quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java

  • A single BlockingQueue<SessionMessageEvent> holds events from all sessions.
  • One background thread named QFJ Message Processor (a daemon thread) drains the queue and calls session.next(message) for each event via SessionMessageEvent.processMessage().
  • The thread is started via blockInThread(), which creates a ThreadAdapter wrapping the block() loop.
  • onMessage() wraps incoming messages into a SessionMessageEvent and puts them on the shared queue.
  • The block() loop polls the queue with a timeout (THREAD_WAIT_FOR_MESSAGE_MS) so it can periodically check the isStopped flag.
  • On stop, remaining queued messages are drained and processed before the thread exits.
  • The getQueueSize(SessionID) method returns the total queue size (single queue for all sessions — there is no per-session view).

Key point for application developers: Because all sessions share a single processing thread, a slow fromApp() callback will delay processing for all other sessions.


4. Thread-per-session model (ThreadPerSessionEventHandlingStrategy)

Class: quickfix.mina.ThreadPerSessionEventHandlingStrategy
Source: quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java

  • A ConcurrentHashMap<SessionID, MessageDispatchingThread> maps each session to its own dispatcher thread.
  • On the first onMessage() call for a given session, a new MessageDispatchingThread is created and started via startDispatcherThread().
  • Each MessageDispatchingThread has its own BlockingQueue<Message> (or watermark-tracked queue) and loops calling session.next(message).
  • Thread name: QF/J Session dispatcher: <BeginString>:<SenderCompID>/<TargetCompID>
  • The Executor can be customised via setExecutor(). The default is DedicatedThreadExecutor, which creates a raw new Thread(command, name).start().
  • On stop, stopDispatcherThreads() enqueues END_OF_STREAM to every dispatcher, sets stopping=true, and waits (polling every 100 ms) until all dispatchers report isStopped.
  • After a dispatcher drains its remaining queue on shutdown, it removes itself from the dispatchers map.

Key point for application developers: Since each session has its own thread, a slow fromApp() for one session does not block others. However, your Application implementation must be thread-safe.


5. The Timer Thread and Session.next()

This is a critical part of the threading model that is orthogonal to the message-processing strategies above.

Class: quickfix.mina.SessionConnector
Source: quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java

5.1 The QFJ Timer thread

A single ScheduledExecutorService (a shared static instance using a QFTimerThreadFactory) runs a SessionTimerTask at a fixed rate of every 1000 ms.

// SessionConnector.java
private static class QFTimerThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable runnable) {
        Thread thread = new Thread(runnable, "QFJ Timer");
        thread.setDaemon(true);
        return thread;
    }
}

The timer is started by startSessionTimer():

protected void startSe...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

📍 Connect Copilot coding agent with [Jira](https://gh.io/cca-jira-docs), [Azure Boards](https://gh.io/cca-azure-boards-docs) or [Linear](https://gh.io/cca-linear-docs) to delegate work to Copilot in one click without leaving your project management tool.

Copilot AI changed the title [WIP] Add documentation for QuickFIX/J threading model docs: Add QuickFIX/J threading model documentation Mar 21, 2026
Copilot AI requested a review from chrjohn March 21, 2026 09:54
@chrjohn
Copy link
Member

chrjohn commented Mar 21, 2026

@copilot please add a reference to the docs to README.MD

Copy link
Contributor Author

Copilot AI commented Mar 21, 2026

@copilot please add a reference to the docs to README.MD

Added a ## threading model section to README.md (after "configuration options") linking to docs/threading-model.md. Commit: a29364e.

Copilot AI requested a review from chrjohn March 21, 2026 16:03
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.

2 participants