Real-life scenario: LedgerStream
LedgerStream reconciles millions of daily transactions from banks, payment providers, and SAP. It must identify mismatches, preserve an audit trail, and finish the daily batch within 45 minutes.
Requirements
- Inputs arrive as large UTF-8 CSV/JSON files and partner HTTP APIs.
- Money must be exact across currencies and rounding rules.
- A duplicate file or event must not duplicate ledger effects.
- Partner APIs may be slow for minutes.
- A corrupt record must not stop all valid records.
- The process must resume safely after a crash.
- Operators need progress, mismatch counts, traces, and a reproducible report.
Domain model
Use records for validated immutable data carriers:
record Money(BigDecimal amount, Currency currency) {
Money {
Objects.requireNonNull(amount);
Objects.requireNonNull(currency);
amount = amount.setScale(currency.getDefaultFractionDigits(),
RoundingMode.HALF_EVEN);
}
}Use a sealed result hierarchy: Matched,
Mismatch, and Rejected. An exhaustive switch
forces handling when a new result type appears.
Processing design
Read files with NIO using bounded buffers and explicit UTF-8. Validate each row into a domain command. Compute a stable idempotency key from partner, file, and transaction identity. Persist checkpoints after bounded chunks.
Use virtual threads for independent blocking partner HTTP calls. Do not create an unbounded request storm: a semaphore caps each partner's concurrency and the connection pool remains the real scarce resource. Each call has a timeout, bounded retry with jitter for safe transient failures, and a circuit breaker in the surrounding application layer.
CPU-heavy matching uses a fixed-size platform-thread executor based
on measured cores. ConcurrentHashMap stores shared indexes
only where memory permits; larger joins belong in a database or external
sort. Never use parallel streams for blocking partner calls.
Correctness
Use BigDecimal, explicit currency/rounding,
Instant for event time, and the partner's
ZoneId for business-day boundaries. Treat duplicate input
as a successful replay of the previous outcome. Isolate malformed rows
into a quarantine report with safe error detail.
Modules
Create modules or strongly enforced packages:
ledger.domain, ledger.ingest,
ledger.match, ledger.partner,
ledger.report, and ledger.runtime. Domain code
does not depend on file, HTTP, or database adapters.
Operations
Build with a pinned JDK 25 toolchain and reproducible JAR. Run as non-root. Record artifact checksum, source revision, input manifest, configuration, and output checksum. Use JFR during performance tests. Publish throughput, queue depth, rejected rows, partner latency, retry count, GC, and completion ETA.
Failure drill
Terminate the process halfway through. On restart, LedgerStream verifies the input manifest, resumes from a committed checkpoint, replays idempotently, and produces the same final checksums. Simulate one slow partner and prove the concurrency cap protects all others.
Decision record
Chosen: immutable records, sealed results, NIO,
BigDecimal, virtual threads for blocking I/O, bounded CPU
pool, checkpoints, idempotency, and JFR.
Rejected: double for money, one thread
per record without limits, parallel streams for network calls, untrusted
Java deserialization, and a single giant mutable map without capacity
proof.