lizhimins opened a new pull request, #149:
URL: https://github.com/apache/rocketmq-flink/pull/149

   ### Context
   
   An acceptance run of this connector against a commercial RocketMQ 5.5.1 
cluster on Flink 1.20.3
   (Application mode, K8s) found a family of defects with the same shape as 
#141: the job stays
   RUNNING, checkpoints succeed, nothing is logged, and the data is wrong or 
absent. This PR carries
   the fixes from that round that are still open, grouped into four topics. 
Each one was verified on
   the cluster with clean-room topics before being committed; the per-defect 
root causes and code
   evidence are in the acceptance report kept outside this repo.
   
   ### What is in this PR
   
   **1. Transactional commits are lost when END_TRANSACTION lands on another 
node (the headline fix).**
   A proxy keeps the transaction context of a half message in its own process 
memory
   (`TransactionDataManager`, keyed by producer group + transaction id, 
expiring after
   `transactionDataExpireMillis`, 30s by default). The committer used to 
resolve the target address
   from its own publish route table, which is populated independently of the 
writer's and may name a
   different node; with two committer subtasks each rolling its own dice, runs 
silently lost half or
   all of a checkpoint while every health signal stayed green. Seven controlled 
experiments (same
   client version, one fresh TRANSACTION topic per run) pin the cause: 
same-address commits succeed
   4/4, cross-pod commits are answered `code=0 SUCCESS` but land nothing 2/2, 
and a same-address commit
   delayed 45s is discarded the same way (the 30s TTL). The fix records the 
address the writer actually
   sent to on the `SendCommittable` right after the send, and the committer 
uses it, falling back to
   route resolution only for restored committables without an address. 
`SendCommittableSerializer`
   moves to version 2 and still reads version 1 state.
   
   **2. Poison records and the remaining dead/misleading options.** A record 
whose deserialization
   throws used to fail the task, which restored from the checkpoint, re-read 
the same record and
   rewrote everything it had already emitted each round. It is now dropped with 
a WARN carrying
   message id, topic, queue and offset, while the split offset advances past 
it; failures raised while
   emitting an already-deserialized record still fail the task, so a real write 
failure cannot hide
   behind the poison path. `send.pending.max` was declared with exactly this 
description but never
   read; the writer now bounds in-flight async sends with a semaphore of that 
size (and releases the
   permit when the send call throws synchronously). The SQL option 
`retry.times` mapped onto a key
   nobody read; it now acts as an alias for `send.retry.times`. 
`InnerConsumerImpl.commitOffset`
   updated a local store with `increaseOnly=true` and never persisted, which 
had no effect at all; it
   now publishes the checkpointed offset, rollbacks included, so the 
broker-side display offset tracks
   the job.
   
   **3. Transactional commits were submitted on a bounded executor that rejects 
under backlog.**
   With 10k records queued, `Commit transaction message` was logged 8055 times 
instead of 10000 and
   694 `RejectedExecutionException`s appeared; the sink stalled at 9650/10000 
while the source had
   already read everything. Commit and rollback now run on the calling thread.
   
   **4. An idle source spun the fetch loop a hundred times a second.** 
`rocketmq.client.poll.timeout`
   defaulted to 10ms. The client poll waits on a blocking queue and returns as 
soon as records arrive,
   so raising the default to 1000ms costs nothing on the data path; it only 
cuts the idle spin to one
   fetch a second. `wakeUp()` merely sets a flag and the consumer deliberately 
has no interruptible
   poll, so this timeout is the sole bound on how long a fetch can outlive a 
close request — one
   second keeps that prompt. A test asserts both the default and a configured 
value reach `poll()`.
   The docs also record the deployment constraint that follows from topic 1: 
the checkpoint interval
   must stay well below the server-side transaction state TTL, because Flink 
only commits at the end of
   a checkpoint.
   
   ### Server-side note (not fixable here)
   
   When the transaction context is missing or expired, 
`AbstractRemotingActivity` maps
   `TRANSACTION_DATA_NOT_FOUND` to `ResponseCode.SUCCESS` and 
`TransactionActivity` discards the
   returned future, so the client sees success while nothing lands and nothing 
is logged. Topic 1
   removes the wrong-node cause on the client side; the TTL cause remains a 
deployment constraint
   (keep the checkpoint interval well below `transactionDataExpireMillis`) 
until the server side is
   addressed separately.
   
   ### Verification
   
   - Clean-room cluster runs on the commercial 5.5.1 deployment: transactional 
sink lands 101/101 at
     parallelism 1 and 2 (missing 0 / unexpected 0 / duplicate 0), and the 
route-refresh fallback
     warning drops from 4 to 0.
   - Module test suite: 138 tests green, including 4 new ones for the 
serializer round trip and v1
     compatibility, the writer recording the address, and the committer using 
it.
   - `mvn spotless:check` under JDK 11 and a full `mvn clean package` of all 
five modules pass.
   
   Happy to split this into per-topic PRs if maintainers prefer; the commits 
are already separated by
   topic.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to