sim_responder
Commercial gear, licensed separately from the engine. The engine, the SDK and every other gear in this catalog are Apache 2.0.
sim_responderis published under the Business Source License 1.1: free to read, copy and use non-production. Production use, including your own traffic, needs a commercial licence. Source influxrig-ent/pkg/gears/sim_responder/, a separate repository from the engine. See the enterprise introduction and the worked tutorial.
The sim_responder gear acts as an ISO8583 authorizer simulator. It is a
pure logic gear: a decoded request arrives on the in port, the responder
applies defaults and rules, and a fields-only response leaves on out for
the downstream codec gear to pack. It never touches the wire: no listener,
no framing, no packing. Transport (TCP/mTLS, framing, per-connection reply
routing) is the io_iso8583 gear's job. Bytes are the codec_iso8583 gear's
job.
| Attribute | Details |
|---|---|
| Source Code | pkg/gears/sim_responder |
| Pairs With | codec_iso8583 on both sides (decode the request, encode the response), typically fed by io_iso8583 in server mode |
| Port IN | Decoded ISO8583 request |
| Port IN Cardinality | Single |
| Port OUT | Fields-only ISO8583 response |
| Port OUT Cardinality | Single |
| Always Emitted Metadata | iso8583.mti, iso8583.mti_class, sim.response_to, sim.correlation_id |
| Conditionally Emitted Metadata | conn.id (propagated from the request, when present) |
| Mandatory Consumed Metadata | iso8583.mti (to resolve the response MTI) |
| Optional Consumed Metadata | conn.id (so the reply routes home) |
| Signals Sent | None |
| Signals Subscribed | sim.start, sim.stop, sim.reset (Control Plane; sim.rate is acknowledged but ignored) |
Typical topology (authorizer simulator reachable over TCP):
io_iso8583 (server :10002) → codec (decode) → sim_responder → codec (encode) → io_iso8583
Replies return on the originating connection: the responder propagates the
conn.id transport metadata, which the io gear's
strict_connection_routing uses to route the reply home.
Reference
fluxrig gears doc sim_responder generates the identity, ports, and configuration below from the gear's manifest, so they stay in lockstep with the code.
| Type | sim_responder |
| Category | logic |
| Status | stable |
| Terminus | transparent |
Responds to ISO8583 requests as an authorizer simulator with configurable rules and latency.
Ports
| Port | Direction | Role | Summary |
|---|---|---|---|
in | input | request | Incoming ISO8583 request from the scheme. |
out | output | response | Outgoing ISO8583 response to the scheme. |
Configuration
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
spec | string | yes | - | Spec reference (store URN or file path). Example: iso8583-v87-ascii:v3.0.0 |
default | object | - | Default response field values. Keys can be field numbers ("39") or aliases ("resp_code"). | |
delay | string | 50ms | Base latency to simulate scheme processing time. | |
deterministic_clock | boolean | false | [Planned] Not yet in a tagged release. When true, $NOW and $RRN use a fixed instant derived from seed instead of the wall clock. Default false keeps timestamps tracking real time. | |
rules | array | - | Conditional response rules, evaluated in order. Each has name, when, set, and an optional per-rule delay. | |
seed | integer | 0 | [Planned] Not yet in a tagged release. Makes $AUTH/$RAND/$ENUM/$NOW reproducible across runs and across a sim.reset. Default 0 keeps replies non-reproducible, seeded from the wall clock. | |
timezone | string | local | The clock that $NOW and $RRN render: local, GMT (or UTC), or a zone name such as America/Montevideo. | |
trigger | enum: on_load, on_control | on_load | on_load processes immediately; on_control drops requests until sim.start arrives. |
Architecture
When to use
- Simulating an issuer authorizer for load testing or development
- Testing timeout, retry, and correlation logic under realistic latency
- Reproducing specific failure modes (insufficient funds, expired card, etc.)
- Demonstrating a deployment without a live issuer connection
Configuration
The full field list, with types and defaults, is in the Reference table above. In brief:
- name: authorizer
type: sim_responder
config:
spec: iso8583-v87-ascii:v3.0.0 # store reference (a file path is roadmap)
trigger: on_load # on_load | on_control
delay: 50ms # base latency
default: # default response fields
39: "00" # approved
38: "$AUTH" # auth code macro
rules: # conditional overrides
- name: Insufficient funds over limit
when: field(4) > 1000000
set:
39: "51"
delay: 10ms # optional per-rule delay override
- name: Expired card
when: field(14) < 2501
set:
39: "54"
delay: 5ms
Rules
Each rule has:
| Key | Type | Required | Description |
|---|---|---|---|
name | string | yes | Rule identifier for logging |
when | string | yes | when expression evaluated against the request |
set | map[string]string | yes | Response field overrides when rule matches |
delay | string | no | Per-rule delay override (replaces base delay) |
The gear evaluates rules in order. The first matching rule wins and its set overrides any previous values. If a rule has a delay, it replaces the base delay for that message (it does not add to it).
The gear refuses a configuration that cannot work when the scenario is applied, instead of answering wrongly. It refuses:
- a
delaythat is not a duration - a rule without a
name, awhenor aset - a
whenthat does not parse - a key that is neither a field number nor an alias of the spec (the gear refuses a subfield alias too). Set the whole field.
- a macro that does not exist
- a
$RANDor$SEQargument that is not a number
When expressions
Rules use the same when expression language as the spec's validation rules:
- Field access:
field(4)orfield(14) - Presence test:
present(2) - MTI access:
mti - Comparisons:
==,!=,<,>,<=,>= - Logic:
&&,||,! - Parentheses for grouping
Amount fields compare numerically, date/time fields compare chronologically, and codes compare as strings.
String literals use single quotes, as in field(48) == 'RS01'. A double-quoted string does not parse. The runtime refuses such a scenario at apply time.
Response MTI
The gear derives the response MTI from the spec's message catalog: pairs_with of the request MTI. A 0100 request gets a 0110 response because the catalog declares they pair.
Echo semantics
The gear automatically copies fields with response_value: echo or response_value: modified in the spec from the request to the response. This includes STAN (DE 11), PAN (DE 2), Amount (DE 4), Terminal ID (DE 41), etc., per the spec's per-MTI rules.
Macros
| Macro | Description |
|---|---|
$AUTH | 6-character alphanumeric auth code |
$RRN | Retrieval Reference Number (YYMMDD + 6-digit sequence), the date in the timezone of the gear |
$STAN | Echoes STAN from request (DE 11) |
$SEQ(name, start) | Named monotonic sequence |
$RAND(min, max) | Uniform random integer in range |
$UUID | UUID v7 |
$NOW | Current time, rendered in the layout the spec declares for the field (MMDD, hhmmss, MMDDhhmmss, YYMM), in the timezone of the gear. A field with no layout is rendered by its format.kind: date as MMDD, time as HHMMSS, and datetime (or any other kind) as MMDDhhmmss |
$ENUM | Random valid value from field's value set |
Delay semantics
The delay in config is the base latency. A matching rule's delay replaces the base delay for that message (it does not add to it). This allows a rule to specify a shorter or longer latency than the base.
delay: 100ms
rules:
- name: Fast approval
when: field(4) < 10000
delay: 1ms # uses 1ms, not 101ms
- name: Slow decline
when: field(4) > 1000000
delay: 500ms # uses 500ms
A paused gear drops requests with a debug log rather than blocking: stalling
would stall the whole pipeline. The configured delay sleeps inside request
processing, and each wire into the gear delivers its messages one at a time, so
1/delay bounds the throughput of one wire: 20 requests per second at the default
50ms. That is the simulated issuer latency, not a bug.
Runtime control
The gear subscribes to Control Plane commands on flux.ctrl.<gear-name>.
Four commands drive it, sent as HTTP on the Mixer and forwarded to the gear
over the bus:
POST /api/v1/control/sim/{action} action: start | stop | rate | reset
The Mixer publishes the command on subject flux.ctrl.<gear-name> with the
gear's name as the address, and waits for the gear to acknowledge receiving
it before answering: the response confirms the command reached a gear, not
that the gear finished acting on it. The body on success is
{"status": "started" | "stopped" | "rate_changed" | "reset"}.
| Command | Args | Effect |
|---|---|---|
sim.start | {"gear": "name"} | Resume processing (clears on_control pause / sim.stop). |
sim.stop | {"gear": "name"} | Pause processing; requests are dropped, not queued. |
sim.reset | {"gear": "name"} | Clear macro sequence counters ($SEQ, $RRN). |
sim.rate | none | Ignored: the responder has no traffic generator, but the command is still acknowledged, since acknowledgment confirms delivery, not that the rate changed. |
Errors
| Condition | Response |
|---|---|
| Body that is not valid JSON, or empty | 400 Invalid JSON |
| Missing gear name | 400 gear is required |
| Unknown action | 400 Invalid action |
| No control-plane connection | 503 Control plane not available |
| No gear acknowledged the command (wrong name, or its command queue is full) | 503, naming the gear |
| Publish failure | 500 Failed to publish command |
Example
- name: authorizer
type: sim_responder
config:
spec: iso8583-v87-ascii:v3.0.0
trigger: on_load
delay: 50ms
default:
39: "00"
38: "$AUTH"
rules:
- name: Insufficient funds
when: field(4) > 1000000
set:
39: "51"
- name: Expired card
when: field(14) < 2501
set:
39: "54"
- name: Fraud suspect
when: field(48) == 'RS01'
set:
39: "59"
44: "FRAUD"
delay: 200ms
When not to use
Do not use sim_responder to prove interoperability. A generated counterparty shares the codec with the thing under test, so a mutual misunderstanding of the spec passes silently. Use Robot Framework or iso8583-tool with an independent implementation for certification.
Rationale & extended info
Why a pure logic gear
The responder never opens a socket, frames a byte, or packs a message. Keeping transport (io_iso8583), codec (codec_iso8583), and response logic (sim_responder) as three separate gears means any of the three can be swapped without touching the others. A real authorizer's logic could sit behind the same io_iso8583/codec_iso8583 pair this simulator uses today. The simulator can point at a different transport without changing a rule.
Why delay is a sleep, not a rate limit
The base delay and each rule's override model the issuer's own processing time, not a throughput cap. Each wire delivers its messages one at a time, so the delay bounds one wire's throughput as a side effect (1/delay). That side effect makes the delay useful for exercising a caller's timeout path deliberately, rather than an accident of implementation.
License
The Business Source License 1.1 covers the gear.