4 of 5

Coroutines

The events-coroutines module adds suspending listeners, suspend emit, and mixed sync/async handlers.

Suspending listeners

Implement SuspendingListener<T> when your handler needs to perform suspend operations like database writes, HTTP requests, or channel sends:

kotlin
class AsyncWelcomeEmail(private val mailer: SuspendingMailer) : SuspendingListener<UserCreated> {
    override suspend fun handle(event: UserCreated) {
        mailer.send("Welcome, ${event.name}!")
    }
}

Register suspending listeners with subscribeSuspending:

kotlin
val bus = SuspendingEventBus(container)
bus.subscribeSuspending<UserCreated, AsyncWelcomeEmail>()

Suspending emit

SuspendingEventBus.emit() is a suspend function that awaits all handlers before returning. Call it from any coroutine scope:

kotlin
coroutineScope {
    bus.emit(UserCreated("Alice"))
    // all listeners (sync and async) have completed here
}

Mixed handlers

A SuspendingEventBus accepts both Listener and SuspendingListener registrations on the same bus. Lambda handlers registered with on are suspending by default:

kotlin
// Plain listener (sync)
bus.subscribe<UserCreated, AuditLogListener>()

// Suspending listener (async)
bus.subscribeSuspending<UserCreated, AsyncWelcomeEmail>()

// Lambda — suspending by default on SuspendingEventBus
bus.on<UserCreated> { event ->
    delay(100)
    println(event.name)
}

All handlers run in sequence during emit, regardless of whether they are sync or async.

Suspend onError

In the coroutines module, onError is a suspend function, so you can perform async work like writing to a database or sending to a channel:

kotlin
val bus = SuspendingEventBus(container, onError = { e ->
    errorChannel.send(e)
})

Migration

You can migrate from events-core to events-coroutinesincrementally:

  1. Add the events-coroutines dependency (it includes events-core transitively).
  2. Replace EventBus with SuspendingEventBus and EventServiceProvider with SuspendingEventServiceProvider.
  3. Existing Listener implementations work as-is — no changes needed.
  4. Convert listeners to SuspendingListener one at a time as needed.

The coroutines module mirrors the core API one-to-one:

kotlin
// Core                    →  Coroutines
// Listener<T>            →  SuspendingListener<T>
// Emitter                →  SuspendingEmitter
// Subscriber             →  SuspendingSubscriber
// EventBus               →  SuspendingEventBus
// EventServiceProvider   →  SuspendingEventServiceProvider
kotlin
dependencies {
    implementation("com.cristianllanos:events-coroutines:1.0.0")
}

Next steps

Learn about thread safety, interface segregation, and once guarantees.