State Machine (EDI lifecycle)
The explicit finite automaton — named states, guarded transitions, full journal — making the life of an EDI message traceable and auditable.
Problem
An INVOIC arrives at 10:00, crosses five components (parser, validator, enricher, router, sender), can be ack'd by the ERP at 14:30, rejected at 15:00, reprocessed at 16:00, archived at 17:00. If state is implicit — scattered across DB fields of several services, or in logs — the EDI support operator cannot answer "where is my invoice?". Worse: a bug skips a step (the ERP acks before we routed), and two weeks later we discover invoices stuck without possible transition.
Forces
- The EDI lifecycle is complex. Six to ten states depending on needs (reception, validation, enrichment, routing, ack, archive).
- Transitions are constrained. We do not jump from [Received] to [Archived] without validating, enriching, delivering.
- Auditability is required. Tax compliance, GDPR, partner SLA — we must prove every transition.
- Error states are real states. Not exceptions to log, but states a message may stay in for days awaiting human action.
- Temporal aspect. Some transitions must happen within a deadline (CONTRL within 24h, ERP ack within 4h).
Solution
Model the lifecycle as an explicit finite state machine with: named states, allowed transitions (DAG), guards (entry conditions), actions (transition effects), output events (Domain Events emitted). The state machine is persisted: each message has its record with current state, history, timestamps. The transition is atomic with the business effect (via Outbox). Implementations: state tables + optimistic lock, or workflow engine (Camunda, Temporal, AWS Step Functions, Apache Airflow for batch). Strong links with Process Manager and Saga Orchestration.
Inbound INVOIC lifecycle:
[Received] ─ AS2 / AS4 message arrived
│
syntactic ok
▼
[SyntacticallyValid] ─ positive CONTRL sent
│
semantic ok
▼
[SemanticallyValid] ─ EN 16931 OK
│
business ok
▼
[BusinessValid] ─ business rules OK
│
enriched
▼
[Enriched] ─ references resolved
│
routed
▼
[Routed] ─ published on Kafka edi.invoices
│
acked by ERP
▼
[AckedByERP] ─ ERP acknowledged receipt
│
processed
▼
[Processed] ─ booked + paid
│
▼
[Archived] ─ stored 10 years S3 Object Lock
Error states (lateral transitions):
- [SyntacticallyInvalid] ← negative CONTRL, technical DLC
- [SemanticallyInvalid] ← APERAK, semantic DLC
- [BusinessRejected] ← APERAK + business workflow
- [EnrichmentFailed] ← retry or degraded
- [RoutingFailed] ← retry
- [ErpRejected] ← exception flow
EDI implementation
Concrete case: Java EDI hub with Spring State Machine or Akka FSM,
or Temporal workflow. Each received INVOIC has a DB row: { messageId, state: 'Received', history: [{state, at, by}], lastActivityAt }.
The EDIFACT parser emits a SyntacticallyValid event,
the state machine checks the guard ("state == 'Received'") and
transitions to SyntacticallyValid. Attempting to skip
a step: rejected. If the validator fails at business stage,
transition to BusinessRejected, APERAK emitted to the
partner, operator workflow triggered. The ops dashboard shows the
distribution: "120 invoices Received, 5 BusinessRejected, 2
EnrichmentFailed". Support answers "Your invoice INV-1234 has
been in Enriched state since 10:32, next step routing". For
French tax audit: the state trace replaces logs to prove no
submitted INVOIC escaped archiving. Tools: Temporal (Uber's
Cadence fork) industrialises this pattern at scale; BPMN 2.0 in
Camunda offers visual modelling.
Anti-patterns
- Implicit scattered state. Fields
is_valid,is_enriched,is_ackedin several tables: no transactional consistency. - Unguarded transitions. A service can directly jump from Received to Archived: pattern neutralised.
- In-memory state machine. Crash → state lost → message in limbo.
- Too many states. 30 microscopic states (parser-1, parser-2, parser-3): unmanageable. Keep business-meaningful granularity.
- No error state. Errors handled as out-of-machine exceptions: invisible in dashboard, lost in logs.
- State machine without timers. No detection of stuck messages: discovered 1 month later.
Related patterns
- Process Manager — parent EIP pattern, explicit state of long processes.
- Saga Orchestration — variant with compensations.
- Process Engine — BPMN/workflow runtime executing the state machine.
- Event Sourcing — transition history can be kept as events.
- Message History — trace of components crossed.
- Validation Pipeline — Syntactically/Semantically/BusinessValid states come out of the pipeline.
Sources
- Camunda — BPMN State Machine. Documentation and best practices to model an EDI lifecycle in BPMN 2.0. docs.camunda.io — State Machine
- Temporal — Workflow as state machine. Modern code-first implementation, Uber Cadence fork. docs.temporal.io
- Spring State Machine. Lightweight Java implementation. spring.io — Statemachine
- UML State Machine spec (OMG). Formal Harel/UML theory. omg.org — UML
- Hohpe G., Woolf B. — Enterprise Integration Patterns, Addison-Wesley 2003. Process Manager (§312) — the parent pattern. enterpriseintegrationpatterns.com — Process Manager
- AWS Step Functions — Workflow Studio. Managed production-grade state machine. aws.amazon.com — Step Functions