Tree: ev_pickup fires only when the command can no longer be rerouted (#594)#615
Conversation
| # Flush pickup events buffered during _launch(). If ev_start | ||
| # aborted the worker, no pickups are emitted (#594). | ||
| pending, self._pending_pickups = self._pending_pickups, [] | ||
| if not self._aborted: |
There was a problem hiding this comment.
(minor)
looks to be:
for node in pending:
if self._aborted:
...i do not see the need for checking aborted twice.
degremont
left a comment
There was a problem hiding this comment.
Harder to review, trusting you here.
b3110e8 to
6e8a2d3
Compare
|
LGTM, how show case the fix in real life? |
|
From AI review:
Rough patch shape: diff --git a/lib/ClusterShell/Propagation.py b/lib/ClusterShell/Propagation.py
@@
- def send_queued(self, ctl):
+ def _send_ctl(self, ctl, pickup_worker=None, pickup_nodes=None):
+ self.send(ctl)
+ if pickup_worker is not None:
+ for node in pickup_nodes:
+ pickup_worker._emit_pickup(node)
+
+ def send_queued(self, ctl, pickup_worker=None, pickup_nodes=None):
"""helper used to send a message, using msg queue if needed"""
if self.setup and not self._sendq:
# send now if channel is setup and sendq empty
- self.send(ctl)
+ self._send_ctl(ctl, pickup_worker, pickup_nodes)
else:
self.logger.debug("send_queued: %d", len(self._sendq))
- self._sendq.appendleft(ctl)
+ self._sendq.appendleft((ctl, pickup_worker, pickup_nodes))
def send_dequeue(self):
"""helper used to send one queued message (if any)"""
if self._sendq:
- ctl = self._sendq.pop()
+ ctl, pickup_worker, pickup_nodes = self._sendq.pop()
self.logger.debug("dequeuing sendq: %s", ctl)
- self.send(ctl)
+ self._send_ctl(ctl, pickup_worker, pickup_nodes)
@@
- self.send_queued(ctl)
+ self.send_queued(ctl, worker, nodes)Then in TreeWorker, drop the new pickup loops added by the PR from both _copy_remote() and _execute_remote(): - # Pickup is fired once the command is being sent to the gateway
- # for each target (#594). On reroute, _launch() calls this method
- # again so a fresh pickup is emitted per (re-)send.
- for node in targets:
- self._emit_pickup(node)
Same removal in _execute_remote(). One important adjustment: PropagationChannel.write() and set_write_eof() can keep calling send_queued(ctl) with no pickup args. That avoids changing their behavior. This keeps the PR’s _emit_pickup() buffering/dedup logic intact, but moves the trigger to the channel layer, where we know whether the command left the local process instead of merely being queued for a gateway that may never come up. Either clarify that this commit is improving but not fully fixing #594 or add the above logic? |
…clustershell#594) Previously ev_pickup fired from _check_ini for every node right after ev_start, regardless of whether the command had actually been sent (with an unreachable gateway, the CTL may sit in _sendq forever and the target is eventually rerouted to a working gateway) or whether the worker had been aborted. Reroutes also double-fired pickup for the same target. Move emission to the actual send sites: - direct path: MetaWorkerEventHandler.ev_pickup hook (Worker._on_start fires once per child node-key) - gateway path: new PropagationChannel._send_ctl helper invoked once per actual channel.send. By construction _send_ctl runs only after the channel has reached setup=True (either via the immediate-send path which requires it, or via send_dequeue after CFG-ACK), and reroute via _relaunch is gated on setup=False -- so a target whose ev_pickup has fired cannot be rerouted. write() and set_write_eof() keep the no-pickup path: subsequent traffic on an already-picked-up node must not double-fire. _emit_pickup gates on _aborted and buffers events before ev_start. The 1:1 ev_pickup-per-node invariant is held structurally by the call sites. Reroute is signaled only by _ev_routing. Closes clustershell#594 Signed-off-by: Stephane Thiell <sthiell@stanford.edu>
6e8a2d3 to
18533f0
Compare
|
@degremont excellent review and AI FTW. I have force-pushed a squashed commit that now does exactly that. And by the way, I also found another simplification when iterating with my AI:
Basically this means that with the existing code structure, My AI warns that:
I tested the new tests before(failed)/after(OK) so I believe they test what we want. Finally, you asked:
The bug is not visible with clush itself (does not rely on For reference, the attached script cs_demo_594.py can be used to reproduce this, here are the results (this PR vs. master): Please re-approve when you get a chance. Feels like a bit of a battle of AIs, haha. Thx! |
degremont
left a comment
There was a problem hiding this comment.
I think we're good now! Good job iterating on that.
Previously ev_pickup fired from _check_ini for every node right after ev_start, regardless of whether the command had actually been sent (with an unreachable gateway, the CTL may sit in _sendq forever and the target is eventually rerouted to a working gateway) or whether the worker had been aborted. Reroutes also double-fired pickup for
the same target.
Move emission to the actual send sites:
write() and set_write_eof() keep the no-pickup path: subsequent traffic on an already-picked-up node must not double-fire.
_emit_pickup gates on _aborted and buffers events before ev_start. The 1:1 ev_pickup-per-node invariant is held structurally by the call sites. Reroute is signaled only by _ev_routing.
Closes #594