[improve][client][broker] PIP-491: Prevent Delivery Stalls by Making the Client Return Exactly the Permits Used by the Broker - #26337
Draft
void-ptr974 wants to merge 5 commits into
Conversation
Assisted-by: Codex (GPT-5)
Keep per-entry permit accounting owned by Consumer and expose a single send result to Shared dispatchers and the command sender.\n\nAssisted-by: OpenAI Codex
Assisted-by: OpenAI Codex (GPT-5)
Assisted-by: Codex/GPT-5.6
Assisted-by: OpenAI Codex
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PIP: #26336
Motivation
For every delivered
CommandMessage, the broker uses a number of consumer permits and the client must eventually return exactly that number. For a native batch, this count (P) is the number of logical messages that are actually deliverable, which can differ from the original batch size during partial redelivery.Pulsar does not currently carry
Pon the wire. Broker layers and the Java client derive related counts independently from batch metadata andack_set. These calculations normally agree, but can diverge when final admission changes the send set, payload processing fails before or during batch expansion, asynchronous work has no terminal outcome, or a broker consumer is recreated while its pooled connection remains active. Returning too few permits progressively reduces receiver capacity and can stall Shared delivery; returning stale or excess permits weakens backpressure.Modifications
This PR implements the PIP-491 contract end to end:
CommandMessage.message_permits = 6without a protobuf default. An upgraded broker sends the field for every delivered command, includingP = 1; field absence is reserved for old-broker compatibility.Pper entry inConsumer.sendMessagesafter pending-ack admission. Entries rejected by filtering/admission or with no deliverable indexes are neither sent nor debited.SendMessagesResult. Consumer accounting, both persistent Shared dispatcher implementations, and command serialization all use that same finalized result, independently of recyclable sender inputs.ack_set, parsed batch metadata, and finally the legacy value of one when the field is absent.Pas a command-local budget during native batch expansion. Successfully handed-off messages claim one unit; skips and unexpanded units remain with the command; the two paths return exactlyPwithout double-returning.ConsumerPermitStaterepresenting one broker-consumer incarnation. Reconnect or consumer recreation replaces the state even when the sameClientCnxis reused. The atomic accumulator and connection event loop revalidate state identity before writingCommandFlow, preventing delayed credit from crossing into a replacement consumer.ack_set.The initial exact guarantee covers persistent Shared delivery (both default and classic implementations) and the Java native-message path. Custom
MessagePayloadProcessoroutput, encrypted/chunked processing, non-Java clients, Key_Shared-specific draining, absolute permit reset/synchronization, and broad dispatcher refactoring remain out of scope.Compatibility
CommandMessage; a proxy that drops unknown fields remains compatible through fallback behavior.No Java public API, configuration, acknowledgment semantic, receiver-queue semantic, or protocol-version negotiation is changed.
Verifying this change
Local validation on the final source tree:
./gradlew quickCheck./gradlew :pulsar-broker:test --tests org.apache.pulsar.broker.service.ConsumerTest :pulsar-broker:checkstyleTestIndependent validation on
home3(Linux, JDK 21) from an exact source archive of commitbd4a56494f3:./gradlew quickCheck: 421 actionable tasks, build successful./gradlew sanityCheck: 584 actionable tasks, build successfulCommandsTest,ConsumerImplTest,MessagePermitAccountingTest,ConsumerTest,EntryBatchIndexesAcksTest,BatchMessageIndexAckTest,CompactedOutBatchMessageTest, andCorruptedBatchMessagePermitTest: 1 skipped, 0 failures, 0 errorsThe targeted matrix covers explicit
P = 1, legacy field absence, full and partial batches, boundedack_setcardinality, filtering and pending-ack rejection, both Shared dispatcher implementations, finalized-value lifetime across recycled sender inputs, write-failure removal, checksum/metadata/decompression/mid-batch failures, native skips, stale epochs, different- and same-ClientCnxreplacement, concurrent returns, queued stale Flow, and repeated corrupted batches without a delivery stall.Does this pull request potentially affect one of the following parts:
CommandMessage.message_permits = 6