# Delay Policy (/sdks/kotlin/how-to/queues/delay-policy)



## Overview [#overview]

A **delay policy** defers when a queued message becomes visible to consumers — you send it now, but nothing can receive it until a countdown you set expires. That's the mechanism behind retry-after-backoff, rate-limited notifications, "remind me in an hour" workflows, and staggering a burst of work so it doesn't hit downstream consumers all at once, all without standing up a separate scheduler.

It works entirely at send time: `QueueMessagePolicy(delaySeconds = delay)` attaches a delay to the message before it's passed to `sendQueuesMessage`. The broker starts the countdown the moment it accepts the message and simply excludes it from delivery until the timer elapses — after that it behaves like any other queued message, available to whichever consumer polls next.

**Gotchas:** the delay is a floor, not a guarantee — the message becomes *eligible* when the timer expires, but actual delivery still waits for a consumer to poll, so don't rely on it for precise scheduling. It's one-shot: there's no recurrence or cron-like behavior, so long or repeating delays need application logic on top. And it's independent of redelivery — a delayed message that's later nacked or times out after delivery follows normal visibility-timeout/retry rules, not the original send-time delay.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Kotlin SDK installed (`implementation("io.kubemq.sdk:kubemq-sdk-kotlin:1.0.1")`)

## Code [#code]

```kotlin title="DelayPolicyExample.kt"
package io.kubemq.sdk.examples.queuesstream

import io.kubemq.sdk.client.KubeMQClient
import io.kubemq.sdk.queues.QueueMessagePolicy
import io.kubemq.sdk.queues.queueMessage
import kotlinx.coroutines.runBlocking

private const val ADDRESS = "localhost:50000"
private const val CLIENT_ID = "kotlin-queues-delay-policy"
private const val CHANNEL = "kotlin-queues.delay-policy"

fun main() = runBlocking {
    val client = KubeMQClient.queues {
        address = ADDRESS
        clientId = CLIENT_ID
    }

    client.use {
        try {
            client.createQueuesChannel(CHANNEL)

            // Send messages with different delay values
            val delays = intArrayOf(1, 3, 5)
            for (delay in delays) {
                client.sendQueuesMessage(queueMessage {
                    channel = CHANNEL
                    body = "Delay ${delay}s".toByteArray()
                    policy = QueueMessagePolicy(delaySeconds = delay)
                })
                println("Sent message with ${delay}s delay.")
            }

            // Poll as messages become available after their delay
            println("\nPolling as messages become available...")
            repeat(3) {
                val response = client.receiveQueuesMessages {
                    channel = CHANNEL
                    maxItems = 1
                    waitTimeoutMs = 10000
                    autoAck = true
                }
                if (response.messages.isNotEmpty()) {
                    println("  Received: ${String(response.messages.first().body)}")
                }
            }
        } finally {
            try { client.deleteQueuesChannel(CHANNEL) } catch (_: Exception) {}
        }
        println("Done.")
    }
}
```

## How It Works [#how-it-works]

* `QueueMessagePolicy(delaySeconds = n)` makes the message invisible for `n` seconds.
* Messages with shorter delays become available first (1s, then 3s, then 5s).
* The long `waitTimeoutMs = 10000` allows the poll to wait for delayed messages to become available.
* Useful for scheduled tasks, rate limiting, or retry backoff patterns.

## Related [#related]

* [Delayed Messages](/sdks/kotlin/how-to/queues/delayed-messages)
* [Expiration Policy](/sdks/kotlin/how-to/queues/expiration-policy)
* [Queues Reference](/sdks/kotlin/reference/queues)
