Skip to content
Bluetape4k docs2.0

JDK 25 adapter for immutable TenantId propagation in Reactor subscriber Context. It installs no default tenant, global hook, or automatic context propagation. This manual connects that purpose to the current build, source entry points, tests, configuration resources, and lifecycle evidence instead of duplicating the README feature list.

Use bluetape4k-tenant-reactor when a reactive pipeline must carry an authorized TenantId in Reactor subscriber Context. Bind once at the subscription boundary and read through ContextView downstream. The adapter is appropriate when explicit propagation is preferred over global hooks or automatic context propagation.

dependencies {
implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>"))
implementation("io.github.bluetape4k:bluetape4k-tenant-reactor")
}

Gradle project path: :bluetape4k-tenant-reactor. Source directory: bluetape4k/tenant-reactor.

The first source-level concepts to inspect are ReactorTenantContext. File names are navigation anchors; read each declaration and its tests before treating it as a public contract.

Bind at contextWrite and read lazily with deferContextual:

val result = Mono.deferContextual { context ->
service.find(ReactorTenantContext.requireCurrent(context))
}.contextWrite { context ->
ReactorTenantContext.withTenant(context, TenantId("clinic-a"))
}

withTenant returns a derived immutable Context; it does not mutate the input context.

Entry pointWhat to verify
ReactorTenantContext.currentOrNullRead an optional TenantId from a ContextView.
ReactorTenantContext.requireCurrentRequire the binding and fail with the common missing-context exception when absent.
ReactorTenantContext.withTenantDerive a new Context containing the canonical TenantId.

Call withTenant once near the subscription boundary and use deferContextual where a downstream component needs the tenant. Do not call Context.put for every signal, install a global Hooks bridge, or copy the tenant into a mutable registry.

The current build declares these integration edges:

api(project(":bluetape4k-tenant"))
api(libs.reactor.core)

Both dependencies are public API edges: consumers receive the common tenant contract and Reactor Context types with this adapter.

The adapter has no configuration properties, global registration, or automatic-propagation switch. The application chooses the subscription boundary explicitly in the pipeline.

currentOrNull returns null for an unbound ContextView; requireCurrent throws the common MissingTenantContextException. Cancellation ends the subscriber lifecycle together with its context. The adapter provides no default, fallback, or duplicate-recovery policy.

Do not expose tenant values through logs, exceptions, MDC, or metric tags. Binding-failure telemetry should use bounded carrier/stage labels and existing correlation or trace identifiers.

Run the module test task:

Terminal window
./gradlew :bluetape4k-tenant-reactor:test --no-configuration-cache

Representative test anchors:

No dedicated workshop path is registered in the manual manifest. Use the module README and the representative tests above as runnable evidence.

The adapter does not authenticate tenants, parse headers, map HTTP errors, install Reactor hooks, or bridge automatically to coroutine ReactorContext. Each boundary must opt into propagation explicitly.