Skip to main content

FIX Operations

The FIX integration-adapter plugin runs on adapter pods and manages live FIX sessions. Each adapter instance owns exactly one FIX session, validates and decodes incoming messages, hands them to the pipeline, and routes results to the configured target.

For initial setup, see FIX Configuration. For sequence-number recovery, see Sequence number recovery below.

The platform manages your side of the session: it establishes and maintains the connection, tracks sequence numbers, sends heartbeats, and reconnects. It does not control the counterparty. Problems that originate on the counterparty or venue side (their session configuration, their sequence state, a venue outage, or throttling they apply) and the correctness of the FIX data dictionary you supply are outside platform support. The event log shows which side a failure came from; counterparty-side issues are resolved with the venue's technical support.

Supported roles

RoleDescriptionWhen to use
INITIATORThe adapter dials a remote counterparty at a configured host and port.You are a market participant connecting to a venue or broker.
ACCEPTORThe adapter listens on a configured port for inbound connections from counterparties.You are a venue or gateway receiving orders.

Role is selected per connection in the adapter configuration. A single platform deployment can run many adapters in mixed roles simultaneously.

Durability

The platform owns FIX session durability end to end. Session state lives in the centralized database the platform already uses for configuration and lease management, so any pod in the pool can take over a session on graceful failover without depending on the previous pod's local disk.

On a planned shutdown or rolling upgrade, the session performs a graceful logout: it sends a FIX Logout and waits briefly, within a bounded window so shutdown stays prompt, for the counterparty's Logout acknowledgment before closing. The counterparty observes a clean session logout rather than an unexpected disconnect, and the session resumes on the new pod with no operator action. Across a non-graceful termination (kernel OOM, node loss), the session may need a sequence-number reconciliation with the counterparty before resuming. See Sequence number recovery below.

Each session declares its persistence behavior through the durabilityMode field, which controls whether message bytes are written to the platform store. The default is FULL (every outbound message persisted before the wire) and is the right choice for almost every production session. Tactical replayable feeds may use NONE, in which case the session must be paired with ResetSeqNumFlag=Y on logon so each restart negotiates a fresh sequence space. See Durability mode for the full comparison.

Behavior under load

Under sustained load or a downstream slowdown, the platform applies a graduated response that protects the pod from memory exhaustion and protects the counterparty from silent message loss.

LayerWhat happensWhat it protects against
Bounded blocking queuesWhen the pipeline falls behind, the adapter's bounded queues (a blocking put-rejection handler on the worker pool and a bounded inbound dispatcher queue) block the network thread that is submitting the work. While that thread is blocked the adapter stops reading the socket, so TCP flow control advertises a zero window and the counterparty pauses sending.Runaway in-memory queue growth.
Protective disconnectWhen blocking alone cannot keep the pod safe, the adapter cleanly disconnects the FIX session rather than continuing to accumulate work, then attempts to reconnect on its standard interval. Two conditions trigger it: the bounded queue reaching its depth limit, or JVM heap usage staying above 0.95 for about 60 seconds.Pod-wide OOM kill.

The thresholds and queue sizes that drive each layer are sized automatically by the platform from the pod's available memory and CPU. Operators tune the response by adjusting pod resource limits, not connector fields. See Scaling and Helm reference.

Whether in-flight or queued messages are recovered when the session reconnects depends on the session's protocol configuration and the counterparty's own behavior. Verify recovery semantics against the specific counterparty's integration spec before relying on the protective disconnect as a safety mechanism in production.

The delivery rule underneath all of this: every inbound message is fully processed, held under explicit backpressure, or explicitly moved to a recoverable dead-letter state; none is silently discarded. The one exception is connection teardown, where the message is still marked recoverable and the counterparty's standard resend covers the gap after reconnect (provided the session runs durabilityMode: FULL and the counterparty honors resend requests).

Monitoring signals

SignalMeaningAlert when
pipelineQueueDepthCurrent number of messages awaiting processing.Depth climbs toward capacity and stays there.
isBackpressureActiveTrue when the pipeline is throttling the network read loop.True continuously for more than a few seconds.
heapPressureActiveTrue when JVM heap usage is above the pressure threshold.True continuously for more than a few seconds. Persistent heap pressure indicates undersized pod memory.
backpressureDisconnectActiveTrue after the adapter has triggered a protective disconnect, until the pipeline drains and the session reconnects.Any true value in production. Investigate why the pipeline could not keep up.

Backpressure warning events are emitted to the event log at most once every ten seconds per session, so a single warning per minute of sustained load is expected behavior, not event loss.

Session metrics (Prometheus)

Per-session series for alerting and trending; each carries a session label.

SeriesMeaningAlert when
connector_engine_info{protocol="fix", version, variant}Constant 1; the tags identify the engine binary in use, so latency comparisons across builds are attributable.Not an alert signal.
fix_session_up1 while the session is logged on.== 0 during scheduled session hours.
fix_session_disconnects_total{clean}Session terminations; clean=false means no Logout handshake completed.Any unclean disconnect; a rising clean rate outside schedule boundaries.
fix_session_rejects_total{type}Messages the counterparty refused: session (transport-level) or business (application-level).Non-zero rate in steady state.
fix_session_resend_requests_total{direction}Sequence-gap recovery requests: in (counterparty detected a gap) or out (we did).Sustained rate; a resend storm means repeated gaps, not routine recovery.
fix_session_sequence_resets_total{gap_fill}Sequence resets received; gap_fill=false forcibly advances sequence numbers and can skip messages.Any gap_fill=false reset.
fix_session_next_sender_seqnum / ..._target_seqnumLive sequence state, for gap monitoring and end-of-day checks.Divergence from the counterparty's records.
fix_session_rtt_secondsHeartbeat round-trip on this pod's clock (probe must be enabled via rttProbeIntervalMs).Sustained growth: network path or counterparty degradation.
fix_inbound_backpressure_block_ms / fix_outbound_backpressure_block_msMilliseconds producers spent blocked on a full queue, recorded only when saturation actually occurs.increase(..._sum[5m]) > 5000 sustained: something downstream of the full queue cannot keep up, and latency percentiles are inflated by design while the platform protects against loss.
fix_inbound_nacked_total{reason}Inbound messages explicitly nacked instead of processed: observer_exception (a route crashed on the message; it went to the dead-letter state for replay) or teardown_reject (connection teardown; the counterparty's resend covers it).Any observer_exception in steady state: a route is failing on live traffic.
fix_outbound_deferrals_totalOutbound messages held for replay because the session was not yet send-ready (logon in flight or connection bounce); replayed in order on the next logon.Sustained growth without a matching drain: the session is not coming back.
{
"fixSocketType": "ACCEPTOR",
"sessionSettings": {
"sessions": [
{
"BeginString": "FIX.4.4",
"SenderCompID": "ACME_GW",
"TargetCompID": "VENUE_X",
"SocketAcceptPort": 5100,
"HeartBtInt": 30
}
]
}
}

The platform auto-sizes its protective queues and pressure thresholds to the pod's available memory and CPU. To support a larger sustained workload, raise the pod's resource limits through Helm values. See Scaling.

Sequence number recovery

FIX sessions track every message in each direction with a sequence number. The platform manages these counters automatically across reconnects; operators do not configure or maintain them in normal operation.

If a session repeatedly fails to reach logon and the event log reports a sequence-number mismatch, the counters have drifted past what the protocol can self-reconcile. Two recovery options are available in the Portal session controls:

OptionWhat it doesWhen to use
Update SeqSets the sender and target sequence numbers to specific values you provide. This is the sequence-only control and does not reset counters to 1. Changing the live sequence numbers can trigger an immediate logout and re-logon as the session realigns with the counterparty. Like Hard Reset, this operator-initiated action emits an ERROR-level event, so both actions are recorded; the difference between them is destructiveness, not whether the action is captured.The default first step. Use it when the venue's technical support has told you the exact numbers they expect on their side. Do not set numbers manually without that guidance.
Hard ResetResets both the sender and target sequence numbers to 1 and force-drops the connection. This action is irreversible, emits an ERROR-level event, and requires a destructive-action confirmation in the Portal.Only when the counterparty has also reset to 1 on their side, or when a session is being re-established from a known-clean baseline. It is not a soft reconnect.

If neither option resolves the issue, contact the venue's technical support and follow their direction. Automatic tracking requires ResetOnLogon=N (the default); see FIX Configuration.

Troubleshooting

SymptomLikely causeAction
Adapter pod restarts with exit code 137 (OOMKilled)Pod memory limit too low for the workload, or a downstream system is absorbing heap faster than backpressure can propagate.Raise adapter.resources.limits.memory in Helm values. See the capacity table in Scaling.
Session disconnects repeatedly under loadPipeline cannot keep up; the adapter is triggering its protective disconnect.Increase adapter CPU limits, increase downstream target capacity, or reduce the counterparty's send rate.
isBackpressureActive: true persistentlyPipeline is undersized for the load.Raise adapter replica count or per-pod CPU limits. Investigate the downstream target.
heapPressureActive: true persistentlyPod memory is undersized.Raise adapter.resources.limits.memory.
Session logs on but no messages arriveAcceptor port not reachable from counterparty, or TargetCompID mismatch.Check the Kubernetes service for the acceptor port. Verify CompIDs match the counterparty's configuration exactly.
Session repeatedly fails to reach logon with a sequence-number mismatchCounters have drifted past what the protocol can self-reconcile.Follow the Sequence number recovery procedure above.

See also