Cancel Subscription
Cancel a KubeMQ events store subscription by cancelling its coroutine job using the Kotlin SDK.
Overview
Every events store subscription opens a long-lived stream to the broker — a coroutine Job collecting a Flow of delivered events until you tell it to stop. Cancelling that Job is how you release the stream deliberately: shutting down a worker, rotating consumers, or tearing down a coroutine scope without leaking connections or leaving a dangling stream on the server.
Internally, subJob.cancel() stops the coroutine collecting subscribeToEventsStore's Flow, which propagates the cancellation down to the underlying stream and detaches from the broker-side subscription registration.
Gotchas: cancelling only stops this subscription — the channel keeps storing every event published afterward, so nothing is lost, and a fresh subscription with StartFromFirst or StartAtSequence picks up exactly where this one left off. Coroutine cancellation is cooperative — if a collector is mid-callback when cancel() is called, that invocation still completes before the Flow actually stops.
Prerequisites
- KubeMQ server running on
localhost:50000 - Kotlin SDK installed (
implementation("io.kubemq.sdk:kubemq-sdk-kotlin:1.0.1"))
Code
package io.kubemq.sdk.examples.eventsstore
import io.kubemq.sdk.client.KubeMQClient
import io.kubemq.sdk.pubsub.StartPosition
import io.kubemq.sdk.pubsub.eventStoreMessage
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.concurrent.atomic.AtomicInteger
private const val ADDRESS = "localhost:50000"
private const val CLIENT_ID = "kotlin-events-store-cancel-subscription"
private const val CHANNEL = "kotlin-events-store.cancel-subscription"
fun main() = runBlocking {
val client = KubeMQClient.pubSub {
address = ADDRESS
clientId = CLIENT_ID
}
client.use {
val receivedCount = AtomicInteger(0)
// 1. Start subscription
println("1. Starting events store subscription...")
val subJob: Job = launch {
client.subscribeToEventsStore {
channel = CHANNEL
startPosition = StartPosition.StartNewOnly
}.collect { msg ->
val count = receivedCount.incrementAndGet()
println(" [$count] Received: seq=${msg.sequence} ${String(msg.body)}")
}
}
delay(300)
// 2. Send messages while subscribed
println("2. Sending persistent events while subscribed...")
repeat(3) { i ->
client.publishEventStore(eventStoreMessage {
channel = CHANNEL
body = "Message ${i + 1}".toByteArray()
})
delay(200)
}
delay(500)
// 3. Cancel subscription
println("\n3. Cancelling subscription...")
subJob.cancel()
println(" Subscription cancelled.")
// 4. Send more messages (should not be received)
println("4. Sending more messages after cancel...")
repeat(3) { i ->
client.publishEventStore(eventStoreMessage {
channel = CHANNEL
body = "Post-cancel message ${i + 1}".toByteArray()
})
}
delay(500)
println("5. Received ${receivedCount.get()} messages (before cancel).")
println("\nCancel subscription example completed.")
}
}How It Works
- The subscription runs in a coroutine job; cancelling the job stops the Flow collection.
- Post-cancel messages are still persisted but not delivered to the cancelled subscriber.
- Re-subscribing with
StartFromFirstorStartAtSequencecan replay missed messages.
Related
Was this page helpful?