process(...) still resolved the same tenant and integration setting once per event. One tenant, 50 events, 50 database lookups before the hot path even reached shipment ingestion.
The fix was not a global cache. A global tenant cache would create stale security behavior and make feature flags harder to trust. The right cache lived inside one poll batch:
Map<UUID, TenantContext> tenantsById = new HashMap<>();
for (DeliveryGatewayTrackingEvent event : events) {
process(event, tenantsById);
messageIds.add(event.messageId());
}
process(...) now uses computeIfAbsent to authorize each tenant once per poll. Every poll still checks whether the tenant has delivery-gateway enabled. Nothing survives across polls. The latency win comes from removing repeated reads, not weakening the gate.
What surprised me was how easy this bug was to miss. The system could pass duplicate-message tests, tenant-scope tests, and manual exception flow tests while still failing a real throughput target. It needed the acceptance test with 50 actual Redis messages and PostgreSQL writes to reveal the hidden cost.
The database boundary still does the hard work
The consumer job is only the outer shell. The correctness boundary lives in ShipmentEventIngestionService.upsertFromEvent(...).
That service takes the event, normalizes carrier, tracking number, status, timestamps, snapshots, and metadata. It builds an idempotency key under the tenant id. It locks that key with pg_advisory_xact_lock. It upserts the shipment, inserts the event with on conflict do nothing, updates the visible shipment status only when the event timestamp is not older, writes audit records, then asks ClaimAutoCaseService whether the status deserves a case.
Only three statuses create default cases: failed_attempt, returned, and exception. A delivered scan does not open a claim. An unknown scan does not open a claim. The tracking timeline records context, but operations work begins only when the event status represents an operational exception.
That separation matters because not every carrier signal should become work. A tracking system records facts. A claims system creates ownership.
The result
The regression test that mattered is blunt: publish a valid event and then an invalid event in the same Redis batch. Run pollOnce(). Assert that no shipment event and no claim case exist, and that both Redis messages remain pending.
That test now passes.
The throughput proof also passes: 50 delivered events process in under 1 second locally, and because they are delivered events, they create zero claim cases. The duplicate stream test publishes two messages with the same source event and gets one shipment event, one claim case, and zero pending Redis messages after successful processing.
The lesson here is not "ack after commit" as a slogan. The real rule is narrower: if one system owns retry visibility and another system owns business durability, the retry signal must not be cleared until the business fact is committed.