Propagate tenant/organization id from Kafka headers through async handler threads via a ThreadLocal context holder
Keep tenant id out of message payloads when possible; carry it in a Kafka header so routing can happen without deserializing the body. On the consumer side, extract once and push into a TenantContextHolder ThreadLocal before dispatching to async handlers.
organizationId (or tenantId) on every record.CollectionEvent(organizationId, payload)).TenantContextHolder.set(orgId); always clear in finally.DelegatingSecurityContextExecutor-style wrapping or set inside the runnable, NOT by relying on InheritableThreadLocal across a long-lived pool.TenantContextHolder with over a plain .set/get/clearThreadLocal<String>organizationId from headers; reject records missing it.organizationId explicitly (don't depend on ThreadLocal across queue boundaries).TenantContextHolder.set(event.orgId); try { handle(event); } finally { TenantContextHolder.clear(); }.