Skip to content

Pulsar: producer deduplication (#3185)#3212

Merged
jeremydmiller merged 1 commit into
mainfrom
feat/pulsar-producer-dedup-3185-v2
Jun 23, 2026
Merged

Pulsar: producer deduplication (#3185)#3212
jeremydmiller merged 1 commit into
mainfrom
feat/pulsar-producer-dedup-3185-v2

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3185. Final issue of the Re-Evaluate Pulsar Integration epic — also closes #3176.

(Rebased replacement for #3211, which became conflicting after the JSON-schema PR #3210 merged; identical content, conflicts with #3210 resolved so schema + dedup coexist.)

Opt-in producer→broker deduplication on a sending endpoint:

opts.PublishMessage<OrderPlaced>()
    .ToPulsarTopic("persistent://public/default/orders")
    .EnableDeduplication();   // optional stable producer name: EnableDeduplication("orders-producer")

How it works

  • The producer is created with a stable producer name and stamps a monotonic per-message sequence id (Pulsar dedups on producer-name + sequence-id).
  • The sequence id is cached by Envelope.Id, so a repeat send of the same envelope (e.g. an outbox resend after a transient failure) reuses its id and the broker discards the duplicate, while a brand-new envelope always gets the next id and is delivered.
  • The counter is seeded from the clock so a fresh producer session never reuses ids from a prior one (DotPulsar 5.1.2 exposes no broker LastSequenceId to resume from).

Scope

  • Producer→broker dedup only, not end-to-end exactly-once; requires broker deduplication enabled on the namespace/topic.
  • Transactions deferred: DotPulsar 5.1.2 exposes no public transactions API (only exception types) — matches the epic's declared non-goal.

Acceptance criteria

  • ✅ Producer dedup is selectable and proven to suppress duplicate sends — integration test (resending_the_same_envelope_is_deduplicated_by_the_broker: resent envelope dropped, distinct one delivered → 2 messages from 3 sends) against a real broker.

Tests / build


10th and final child of epic #3176. With this merged the epic is complete: #3186, #3178, #3181, #3177, #3179, #3180, #3184, #3182, #3183, #3185.

🤖 Generated with Claude Code

Opt-in producer→broker deduplication on a sending endpoint:

    opts.PublishMessage<OrderPlaced>().ToPulsarTopic(topic).EnableDeduplication();

The producer is created with a stable producer name and stamps a monotonic
per-message sequence id (Pulsar dedups on producer-name + sequence-id). The
sequence id is cached by Envelope.Id, so a repeat send of the same envelope
(e.g. an outbox resend after a transient failure) reuses its id and the broker
discards the duplicate, while a brand-new envelope always gets the next id and
is delivered. The counter is seeded from the clock so a fresh producer session
never reuses ids from a prior one (DotPulsar 5.1.2 exposes no broker
LastSequenceId to resume from).

This is producer->broker dedup only, not end-to-end exactly-once, and requires
broker deduplication to be enabled on the namespace/topic. Pulsar transactions
are NOT exposed by DotPulsar 5.1.2 (only exception types) and are deferred /
out of scope, matching the epic's declared non-goal.

Tests: resending the same envelope is deduplicated by the broker (a distinct
envelope is delivered) verified against a real broker; config unit test. Docs:
Producer Deduplication section noting the producer->broker-only boundary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 91f11d1 into main Jun 23, 2026
25 checks passed
This was referenced Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pulsar: producer dedup (transactions blocked upstream) Re-Evaluate Pulsar Integration

1 participant