You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Summary
Add `Publisher.PublishAfter(ctx, topic, msg, delayMs)` to the queue
extension: a fresh message inserted into the topic, made visible to
subscribers only after `delayMs` from now. Distinct from
`Delivery.Nack(requeueAfterMillis)`:
- `Nack` is "this delivery failed, try again" — it bumps `retry_count`
and eventually trips DLQ.
- `PublishAfter` is "postpone this work" — `retry_count` resets to 0,
DLQ stays available for true failures.
The split keeps both signals meaningful. Use `PublishAfter` for
self-driven poll loops (each cycle is a fresh message, not a retry).
Use `Nack` for processing failures.
SQL backing in `extension/queue/mysql`:
- New `visible_after BIGINT UNSIGNED NOT NULL DEFAULT 0` column on
`queue_messages`. Default 0 means immediately visible — back-compat
for any existing rows.
- `messageStore.InsertDelayed(ctx, topic, messages, visibleAfterMs)`
is the underlying primitive. `Insert` is now a thin wrapper that
passes `visibleAfterMs = 0`.
- `FetchByOffset` gains a `nowMs` parameter and an
`AND visible_after <= ?` predicate so subscribers skip rows whose
delivery is still deferred.
- `MoveToDLQ` writes `visible_after = 0` explicitly: any delay on the
original message has already been consumed by the time it failed.
The first consumer of `PublishAfter` is the orchestrator's poll-driven
`buildsignal` loop, which lands in the stacked PR on top of this one.
## Test Plan
- `make mocks gazelle tidy fmt lint check-tidy check-gazelle check-mocks`
— all green.
- `make test` — 35 unit tests pass, including new coverage for
`PublishAfter` (positive/zero/negative delay, closed-publisher) and
for `FetchByOffset` skipping deferred rows.
- `make build` — all targets compile.
## Issues
**`PublishAfter`** inserts a fresh message that becomes visible to subscribers only after `delayMs`. It is distinct from `Nack(requeueAfterMillis)` even though both can produce "next delivery happens at T+delay":
22
+
23
+
-`Nack` is "this delivery failed, try again" — it bumps `retry_count` and eventually trips DLQ.
24
+
-`PublishAfter` is "postpone this work" — `retry_count` resets to 0, DLQ stays available for true failures.
25
+
26
+
Use `PublishAfter` for self-driven poll loops (e.g. the orchestrator's `buildsignal` consumer re-publishing itself between `Status` calls). Use `Nack` for processing failures.
27
+
20
28
### Subscriber
21
29
Consumes messages from topics with per-subscription configuration.
|`queue_subscriber_heartbeats`| Active subscriber tracking |`(consumer_group, topic, subscriber_name)`|
114
114
115
+
`queue_messages` has a `visible_after BIGINT UNSIGNED NOT NULL DEFAULT 0` column that supports `Publisher.PublishAfter`: subscribers' `FetchByOffset` skips rows where `visible_after > now`. Default 0 means immediately visible, so existing rows continue to behave as before — the column is back-compatible.
116
+
115
117
See `schema/` for full SQL definitions. See the [RFC](../../doc/rfc/sql-queue-rfc.md#database-schema) for field-level documentation.
0 commit comments