lhotari commented on PR #1476:
URL: 
https://github.com/apache/pulsar-client-go/pull/1476#issuecomment-4370610464

   ## Local review by Claude Code
   
   This is a code review performed locally by Claude Code (model: Opus 4.7). No 
automated tools posted this; a human reviewer ran `/pr-review` against the diff 
and metadata.
   
   **Verdict:** Approve. Bug is real, fix is correct, tests are thorough.
   
   ### Summary
   The race is real and the fix is well-implemented. `GetConnection → _setConn 
→ AddConsumeHandler → RequestOnCnx` mirrors the existing producer pattern in 
`producer_partition.go:320-345`. Failure paths cleanly delete the handler, 
restore the previous connection, and route the timeout `CLOSE_CONSUMER` over 
the same `cnx` rather than re-resolving from the pool (which is actually 
slightly more correct — consumer IDs are per-connection).
   
   ### Correctness checks confirmed
   - `cnx` from `cnxPool.GetConnection` is identical to `res.Cnx` from 
`RequestOnCnx(cnx, ...)` (`internal/rpc_client.go:175-186`), so removing the 
post-success `_setConn(res.Cnx)` is safe.
   - `pc.conn` is `atomic.Pointer[internal.Connection]` (not `atomic.Value`), 
so `pc.conn.Store(nil)` does not panic.
   - Reconnect callers discard the return value into a retry loop 
(`consumer_partition.go:2055-2114`); the `prevConn` rollback preserves prior 
semantics that `pc.conn` survives a failed reconnect unchanged.
   
   ### Nits (non-blocking)
   1. **Triplicated cleanup block** — the "delete handler + restore prevConn 
(or store nil)" sequence is inlined three times. A small `restoreConn := func() 
{ ... }` closure or a `defer` gated on a `subscribed` flag would be cleaner.
   2. **`_getConn()` invariant comment** at `consumer_partition.go:2496` claims 
conn is non-nil for the lifetime of the consumer. In practice it's only non-nil 
after the first successful subscribe (true before this PR too — 
initial-subscribe failure left the zero-value pointer). Worth tightening the 
comment in a follow-up.
   3. **Test `connectedCh` drain** — 
`TestGrabConn_HandlerRegisteredBeforeSubscribe` and 
`TestGrabConn_BrokerFrameDuringSubscribe` hit the success path which spawns `go 
func() { pc.connectedCh <- struct{}{} }()`. Channel is buffered (size 1) so the 
goroutine completes, but draining it (`<-pc.connectedCh`) would assert 
correctness and protect against future buffer-size changes.
   4. **Helper init asymmetry** — `newGrabConnTestConsumerNoConn` initializes 
`pc.availablePermits` but `newGrabConnTestConsumer` does not. A one-line 
comment explaining that only the `MessageReceived` path needs it would help 
future readers.
   
   ### Intent vs implementation
   The PR description's claim that the fix "mirrors the existing pattern in 
`producer_partition.go`" is accurate; the consumer version adds extra 
`prevConn` rollback that the producer doesn't bother with, which is a small 
improvement.


-- 
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