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
The identity, ports, and configuration below are generated 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:v2.2.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. | |
rules | array | - | Conditional response rules, evaluated in order. Each has name, when, set, and an optional per-rule delay. | |
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:v2.2.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) |
Rules are evaluated 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).
A configuration that cannot work is refused when the scenario is applied, instead of answering wrongly: a delay that is not a duration, a rule without a name, a when or a set, a when that does not parse, a key that is neither a field number nor an alias of the spec (a subfield alias is refused too: set the whole field), a macro that does not exist, and a $RAND or $SEQ argument 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 check:
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, and the scenario is refused when it is applied.
Response MTI
The response MTI is derived 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
Fields with response_value: echo or response_value: modified in the spec are copied from the request to the response automatically. 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 the
throughput of one wire is bounded by 1/delay: 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:v2.2.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, and the simulator can be pointed 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. Because each wire delivers its messages one at a time, the delay does bound one wire's throughput as a side effect (1/delay), which is what makes it useful for exercising a caller's timeout path deliberately, rather than as an accident of implementation.
License
The gear is licensed under the Business Source License 1.1.