Skip to main content

Built-in Pipeline Behaviors

MediatorK ships seven ready-to-use pipeline behaviors. Drop them into MediatorFactory.create, no boilerplate required.

  1. LoggingPipelineBehavior: logs every request in and out
  2. TimeoutPipelineBehavior: cancels requests that exceed a deadline
  3. RequestCounterPipelineBehavior: counts dispatches per request type
  4. CachingPipelineBehavior: skips the handler on a cache hit
  5. TimingPipelineBehavior: measures handler duration
  6. ErrorTrackingPipelineBehavior: forwards exceptions to crash reporters
  7. TransactionPipelineBehavior: wraps every request in a begin / commit / rollback transaction

LoggingPipelineBehavior

Logs each request as it enters and exits the pipeline, including the result on the exit line. Accepts any (String) -> Unit logger so it works on every platform.

KMP / common (println)

val mediator = MediatorFactory.create(
registrars = listOf(AppRegistrar()),
pipelineBehaviors = listOf(
LoggingPipelineBehavior(logger = ::println),
),
)

Output:

→ GetUserQuery
← GetUserQuery result=User(id=user-1, name=Alice)

JVM: SLF4J

import org.slf4j.LoggerFactory

val log = LoggerFactory.getLogger("Mediator")

LoggingPipelineBehavior(logger = log::info)

Android: Logcat

LoggingPipelineBehavior(logger = { msg -> Log.d("Mediator", msg) })

JS / browser: console

LoggingPipelineBehavior(logger = { msg -> console.log(msg) })

Parameters

ParameterTypeDefaultDescription
logger(String) -> Unit::printlnFunction that receives each log line
orderInt-100Low number = outermost, logs before any other behavior

TimeoutPipelineBehavior

Cancels the downstream pipeline if it does not complete within the given deadline. Throws TimeoutCancellationException (a CancellationException) when the deadline is exceeded.

val mediator = MediatorFactory.create(
registrars = listOf(AppRegistrar()),
pipelineBehaviors = listOf(
TimeoutPipelineBehavior(timeoutMillis = 5_000),
),
)

Parameters

ParameterTypeDefaultDescription
timeoutMillisLongrequiredMaximum allowed duration per dispatch. Must be > 0
orderInt0Position in the behavior chain

RequestCounterPipelineBehavior

Counts how many times each request type has passed through the pipeline.

val counter = RequestCounterPipelineBehavior()

val mediator = MediatorFactory.create(
registrars = listOf(AppRegistrar()),
pipelineBehaviors = listOf(counter),
)

mediator.send(GetUserQuery(id = "user-1"))
mediator.send(GetUserQuery(id = "user-2"))
mediator.send(CreateOrderCommand(cartId = "cart-42"))

counter.countFor(GetUserQuery::class) // 2
counter.countFor(CreateOrderCommand::class) // 1
counter.snapshot() // {"GetUserQuery" to 2, "CreateOrderCommand" to 1}

API

MemberDescription
countFor(KClass<*>)Returns the dispatch count for a specific request class
snapshot()Returns a copy of all counts as Map<String, Long>
reset()Clears all counters

Parameters

ParameterTypeDefaultDescription
orderInt0Position in the behavior chain

CachingPipelineBehavior

Caches handler results by request key for a configurable TTL. On a cache hit the handler is skipped entirely. Best suited for query requests whose results change infrequently.

CachingPipelineBehavior(
ttlMs = 30_000, // cache for 30 seconds
keyFor = { req -> req.toString() }, // default: full toString
)

Use filter to cache most requests while excluding specific types:

CachingPipelineBehavior(
ttlMs = 600_000, // 10 minutes
filter = { it !is CreateBookingCommand && it !is GetBookingQuery },
)
APIDescription
invalidate(key)Remove a single entry
clear()Remove all entries
size()Count of cached entries

Parameters

ParameterTypeDefaultDescription
ttlMsLong60_000Time-to-live per entry in milliseconds
keyFor(Request<*>) -> StringtoString()Cache key function
filter(Request<*>) -> Boolean{ true }When false, the request bypasses caching entirely
orderInt0Position in the behavior chain

TimingPipelineBehavior

Measures how long each request takes and reports it via a callback. Timing is always reported, even when the handler throws.

// KMP / println
TimingPipelineBehavior(onTiming = { name, ms -> println("$name took ${ms}ms") })

// Android — Firebase Performance
TimingPipelineBehavior(onTiming = { name, ms ->
FirebasePerformance.getInstance().newTrace(name).also { it.start(); it.stop() }
})

// JVM — Micrometer
TimingPipelineBehavior(onTiming = { name, ms ->
meterRegistry.timer(name).record(ms, TimeUnit.MILLISECONDS)
})

Parameters

ParameterTypeDefaultDescription
onTiming(String, Long) -> UnitrequiredCallback with (requestName, durationMs)
orderInt0Position in the behavior chain

ErrorTrackingPipelineBehavior

Intercepts every unhandled exception, forwards it to a callback, then rethrows. Use this to wire crash-reporting services without touching handler code.

// Android — Firebase Crashlytics
ErrorTrackingPipelineBehavior { request, error ->
FirebaseCrashlytics.getInstance().recordException(error)
}

// KMP — Sentry
ErrorTrackingPipelineBehavior { request, error ->
Sentry.captureException(error)
}

Parameters

ParameterTypeDefaultDescription
orderIntInt.MAX_VALUEInnermost by default, fires closest to the handler
onError(Request<*>, Throwable) -> UnitrequiredCallback with the request and the exception

TransactionPipelineBehavior

Wraps every request in a transaction: begin() before the handler runs, commit() on success, and rollback() on any exception (which is then rethrown). Implement the small TransactionProvider interface for whatever resource supports begin / commit / rollback — a SQL database, an in-memory store, or your own unit-of-work.

// Adapt your database to the TransactionProvider contract
class DatabaseTransactionProvider(private val db: Database) : TransactionProvider {
override suspend fun begin() = db.beginTransaction()
override suspend fun commit() = db.commitTransaction()
override suspend fun rollback() = db.rollbackTransaction()
}

val mediator = MediatorFactory.create(
registrars = listOf(AppRegistrar()),
pipelineBehaviors = listOf(
TransactionPipelineBehavior(DatabaseTransactionProvider(db)),
),
)

Parameters

ParameterTypeDefaultDescription
transactionProviderTransactionProviderrequiredResource that supports begin(), commit(), and rollback()

Registering multiple built-in behaviors

val counter = RequestCounterPipelineBehavior()

val mediator = MediatorFactory.create(
registrars = listOf(AppRegistrar()),
pipelineBehaviors = listOf(
LoggingPipelineBehavior(logger = ::println, order = -100),
TimeoutPipelineBehavior(timeoutMillis = 5_000, order = -1),
counter,
),
)

Next

Pre / Post Behaviors