Skip to content

Add Nats-Schedule-Msg-Id for deduplicating scheduled messages #8223

@Xayc73

Description

@Xayc73

Proposed change

I would like to propose adding a new Scheduler header:

Nats-Schedule-Msg-Id

When a scheduled message fires, the Scheduler would copy this value from the schedule record into the emitted message as:

Nats-Msg-Id

This follows the existing Scheduler pattern:

Nats-Schedule-TTL -> Nats-TTL
Nats-Schedule-Rollup -> Nats-Rollup

The regular Nats-Msg-Id on the schedule record would keep its current meaning: it deduplicates the schedule write itself. It would not be automatically reused for the emitted message.

I see this as two related parts:

  1. Add Nats-Schedule-Msg-Id

This is the core feature I need. It gives clients a way to assign a deterministic Nats-Msg-Id to the message emitted by the Scheduler.

  1. Decide whether to restrict it to one-shot schedules

There is a question around repeating schedules. Since Nats-Schedule-Msg-Id is static on the schedule record, using it with @every or cron-like schedules would cause multiple emitted messages to reuse the same Nats-Msg-Id. Within the stream duplicate window, later fires could then be suppressed.

Because of that, it may make sense to reject Nats-Schedule-Msg-Id for repeating schedules and allow it only for one-shot schedules. This requires a larger change in validation code, but I can include it if that is the preferred behavior.

Use case

In my use case, multiple independent timers may produce the same logical control message. Each timer has its own schedule record, but they may target the same subject and represent the same logical command.

I need a way to ensure that if two or more timers fire the same logical command, JetStream stream-level duplicate detection stores only one resulting control message.

For example:

  • schedule record A fires to control.subject
  • schedule record B also fires to control.subject
  • both use the same Nats-Schedule-Msg-Id
  • the Scheduler emits messages with the same Nats-Msg-Id
  • JetStream stores only the first emitted control message and treats later ones as duplicates

The payload may differ between timers. In that case, the intended behavior is that the first successfully stored emitted message wins: its payload and headers are the ones consumers see, while later duplicate emits are suppressed by stream-level deduplication.

Contribution

I am willing to contribute this change.

I can implement the core support for Nats-Schedule-Msg-Id.
If maintainers prefer restricting this to one-shot schedules, I can also add validation that rejects Nats-Schedule-Msg-Id for repeating schedules.

Metadata

Metadata

Assignees

No one assigned

    Labels

    proposalEnhancement idea or proposal

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions