DocumentationUser GuideScheduler - Delayed Event Handling

Scheduler User Guide

Kaspr Scheduler is an optional add-on component of KasprApp that provides delayed message delivery to Kafka topics.

What the Scheduler Does

Scheduler lets producers send a message now and have it delivered to a target topic at a specified time.

Typical use cases:

  • Delayed notifications.
  • Deferred retries.
  • Time-based workflow triggers.

Enable Scheduler

Enable scheduler on KasprApp:

  • schedulerEnabled: true
apiVersion: kaspr.io/v1alpha1
kind: KasprApp
metadata:
	name: orders-app
spec:
	config:
		schedulerEnabled: true

Optional tuning:

  • schedulerTopicPartitions: number of partitions for scheduler internal topics.
  • schedulerDebugStatsEnabled: enable periodic scheduler stats logs.

After enabling, scheduler topics are created using your app id prefix:

  • <app-id>-schedule-requests
  • <app-id>-schedule-actions
  • <app-id>-schedule-rejections

Publish a Scheduled Message (ADD)

Send your message to:

  • <app-id>-schedule-requests

Required headers for ADD:

  • x-scheduler-deliver-to: destination topic name.
  • x-scheduler-deliver-at: UTC timestamp in ISO format.

Optional headers for ADD:

  • x-scheduler-action: defaults to ADD if omitted.
  • x-scheduler-request-id: client-defined id used later for cancellation.

Example payload shape:

{
	"key": "order-123",
	"value": {"type": "send-reminder"},
	"headers": {
		"x-scheduler-deliver-to": "reminders-topic",
		"x-scheduler-deliver-at": "2026-05-24T12:30:00Z",
		"x-scheduler-request-id": "reminder-order-123"
	}
}

What to Expect

  • If timestamp is in the future, message is delivered at scheduled time.
  • If timestamp is in the past, message is delivered immediately.

Replace a Scheduled Message (REPLACE)

Use REPLACE when you want to update an existing scheduled message identified by request id.

To replace, publish to <app-id>-schedule-requests with:

  • x-scheduler-action: REPLACE
  • x-scheduler-request-id: <same id used at schedule time>
  • x-scheduler-deliver-to: <destination topic>
  • x-scheduler-deliver-at: <new UTC ISO timestamp>

REPLACE requires both target fields (deliver-to, deliver-at) and identity (request-id).

Replace Semantics

  • If the request id exists, scheduler removes the previous row and inserts the new row.
  • If the request id does not exist, scheduler treats it as a new schedule with that id.
  • If the existing schedule is strictly identical (same time, destination, key, value, headers), scheduler performs a no-op replacement.

Example headers:

x-scheduler-action=REPLACE
x-scheduler-request-id=reminder-order-123
x-scheduler-deliver-to=reminders-topic
x-scheduler-deliver-at=2026-05-24T13:00:00Z

Cancel a Scheduled Message (CANCEL)

To cancel, publish to <app-id>-schedule-requests with:

  • x-scheduler-action: CANCEL
  • x-scheduler-request-id: <same id used at schedule time>

No x-scheduler-deliver-at or x-scheduler-deliver-to is required for CANCEL.

Example headers:

x-scheduler-action=CANCEL
x-scheduler-request-id=reminder-order-123

Cancel Semantics

  • Cancellation is id-based and best effort.
  • If the request id is unknown, no message is canceled.
  • If the message is already being delivered, cancellation may be too late.

Invalid Requests and Rejections

Invalid scheduler requests are sent to:

  • <app-id>-schedule-rejections

Common rejection reasons:

  • Missing x-scheduler-deliver-at for ADD.
  • Missing x-scheduler-deliver-to for ADD.
  • Missing x-scheduler-deliver-at for REPLACE.
  • Missing x-scheduler-deliver-to for REPLACE.
  • Invalid timestamp format for x-scheduler-deliver-at.
  • Missing x-scheduler-request-id for CANCEL.
  • Missing x-scheduler-request-id for REPLACE.

Rejection records include original key/value/headers plus error details.

Delivery Guarantees and Expectations

  • Treat delivery as at-least-once: consumers should be idempotent.
  • Do not rely on global ordering across partitions.
  • Ensure destination topics exist before scheduling traffic.

Production Checklist

  • Use UTC timestamps end to end.
  • Include x-scheduler-request-id on all scheduled messages if you need cancellation or replacement.
  • Start with default partitioning, then increase schedulerTopicPartitions for higher throughput.
  • Monitor rejections topic and scheduler lag/throughput metrics.
  • Keep consumer handlers idempotent to handle duplicate deliveries safely.

Quick Troubleshooting

Message was not delivered

  • Check destination topic exists.
  • Check consumer group is healthy.
  • Check if request was rejected in <app-id>-schedule-rejections.

Message was rejected

  • Validate required headers for selected action (ADD, CANCEL, or REPLACE).
  • Validate timestamp is parseable ISO UTC.

Cancel did not stop delivery

  • Confirm x-scheduler-request-id exactly matches original scheduled request.
  • Confirm cancel arrived before dispatch window.

Replace had no visible effect

  • Confirm x-scheduler-request-id matches the existing scheduled message.
  • Check kms_messages_replace_noop to see if replacement was a strict no-op.
  • Validate replacement timestamp/topic differ from the existing entry when change is expected.

Quick Reference

Action: ADD

  • Topic: <app-id>-schedule-requests
  • Required headers: x-scheduler-deliver-to, x-scheduler-deliver-at
  • Optional headers: x-scheduler-action=ADD, x-scheduler-request-id

Action: CANCEL

  • Topic: <app-id>-schedule-requests
  • Required headers: x-scheduler-action=CANCEL, x-scheduler-request-id

Action: REPLACE

  • Topic: <app-id>-schedule-requests
  • Required headers: x-scheduler-action=REPLACE, x-scheduler-request-id, x-scheduler-deliver-to, x-scheduler-deliver-at