Clean up action goals on client disconnect - #1318
grimgrimberg wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The current finish() implementation can race with concurrent dict mutation and can spawn an unbounded number of threads on disconnect, which can cause runtime errors and operational instability.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR addresses action goal lifecycle cleanup on client disconnect by adding an opt-in cancel_on_disconnect flag to send_action_goal, ensuring per-client action handler state is dropped during Protocol.finish(), and providing tests/documentation for the new behavior.
Changes:
- Add optional
cancel_on_disconnect(defaultfalse) to thesend_action_goaloperation and plumb it through toActionClientHandler. - Implement
SendActionGoal.finish()to drop per-client handler state and asynchronously cancel opted-in goals. - Extend protocol documentation and add unit tests for type validation and disconnect cleanup behavior.
File summaries
| File | Description |
|---|---|
| ROSBRIDGE_PROTOCOL.md | Documents the new cancel_on_disconnect field for send_action_goal. |
| rosbridge_library/test/capabilities/test_action_capabilities.py | Adds tests covering invalid cancel_on_disconnect types and finish() disconnect cleanup/cancel behavior. |
| rosbridge_library/src/rosbridge_library/internal/actions.py | Adds cancel_on_disconnect to ActionClientHandler so the capability can decide disconnect-time cancellation. |
| rosbridge_library/src/rosbridge_library/capabilities/send_action_goal.py | Adds message-field validation, passes cancel_on_disconnect through, and implements finish() cleanup/cancel logic. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| def finish(self) -> None: | ||
| client_handlers = self.client_handler_list | ||
| self.client_handler_list = {} | ||
|
|
||
| for client_handler in client_handlers.values(): | ||
| if client_handler.cancel_on_disconnect and client_handler.send_goal_helper is not None: | ||
| Thread(target=client_handler.send_goal_helper.cancel_goal, daemon=True).start() |
There was a problem hiding this comment.
Addressed in 5dfaaef. Handler add/remove/finish operations now share a lock, finish prevents late re-registration, and opted-in goals are cancelled sequentially by one background worker. Added regression tests for sequential cancellation and post-finish registration.
Summary
Testing
All testing used local simulated ROS nodes only. No robot, vehicle, or external ROS target was contacted.
Fixes #1291