DefaultCoalescingPolicy

Default implementation of CoalescingPolicy.

It deduplicates concurrent calls per resolved key using an in-memory map of in-flight Deferred instances. When the shared deferred completes (success or failure), it is removed from the map so subsequent calls can re-execute the block.

Why ResilientScope and not coroutineScope { async { ... } }? The shared in-flight work must run in a scope that is not the caller's scope. If we used async inside the caller's coroutineScope, that job would be a child of the first caller; when that caller is cancelled (e.g. user navigates away, timeout), the shared job would be cancelled too, and all other callers waiting on the same key would receive kotlinx.coroutines.CancellationException. Coalescing requires that cancelling one caller does not cancel the shared execution for the others. Hence the shared execution is launched in ResilientScope, which is independent of any single caller.

Structured concurrency: The in-flight operation is intentionally not a child of the caller's scope (it lives in ResilientScope). This is the accepted trade-off for request coalescing: the merged work can outlive one requestor so that others still get the result. We do not use kotlinx.coroutines.GlobalScope; ResilientScope is provided by the user and typically tied to application or ViewModel lifecycle, so there is no unbounded lifetime.

Parameters

config

Key (fixed or via CoalesceConfig.keyProvider) for deduplication.

resilientScope

Scope used to launch the shared in-flight execution so it is not cancelled when a single caller is cancelled.

Constructors

Link copied to clipboard
constructor(config: CoalesceConfig, resilientScope: ResilientScope)

Functions

Link copied to clipboard
open suspend override fun <T> execute(block: suspend () -> T): T