-
Notifications
You must be signed in to change notification settings - Fork 6
Improve handling of failed scan tasks and allow reconnect #332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| from .base_controller import BaseController as BaseController | ||
| from .controller import Controller as Controller | ||
| from .controller_api import ControllerAPI as ControllerAPI | ||
| from .controller_vector import ControllerVector as ControllerVector |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| from collections.abc import Iterator | ||
| from dataclasses import dataclass, field | ||
|
|
||
| from fastcs.attributes import Attribute | ||
| from fastcs.methods import Command, Scan | ||
|
|
||
|
|
||
| @dataclass | ||
| class ControllerAPI: | ||
| """Attributes, Methods and sub APIs of a `Controller` to expose in a transport""" | ||
|
|
||
| path: list[str] = field(default_factory=list) | ||
| """Path within controller tree (empty if this is the root)""" | ||
| attributes: dict[str, Attribute] = field(default_factory=dict) | ||
| command_methods: dict[str, Command] = field(default_factory=dict) | ||
| scan_methods: dict[str, Scan] = field(default_factory=dict) | ||
| sub_apis: dict[str, "ControllerAPI"] = field(default_factory=dict) | ||
| """APIs of the sub controllers of the `Controller` this API was built from""" | ||
| description: str | None = None | ||
|
|
||
| def walk_api(self) -> Iterator["ControllerAPI"]: | ||
| """Walk through all the nested `ControllerAPI` s of this `ControllerAPI`. | ||
|
|
||
| Yields the `ControllerAPI` s from a depth-first traversal of the tree, | ||
| including self. | ||
|
|
||
| """ | ||
| yield self | ||
| for api in self.sub_apis.values(): | ||
| yield from api.walk_api() | ||
|
|
||
| def __repr__(self): | ||
| return ( | ||
| f"ControllerAPI(" | ||
| f"path={self.path}, " | ||
| f"sub_apis=[{', '.join(self.sub_apis.keys())}]" | ||
| f")" | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,6 +95,12 @@ async def cancel_all(self) -> None: | |
| async def connect(self) -> None: | ||
| await self.connection.connect(self._settings.ip_settings) | ||
|
|
||
| async def reconnect(self): | ||
| await self.connection.close() | ||
| await self.connection.connect(self._settings.ip_settings) | ||
|
|
||
| self._connected = True | ||
|
Comment on lines
+98
to
+102
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Violates base class contract: Per the base 🐛 Proposed fix: wrap in try-except and log errors async def reconnect(self):
- await self.connection.close()
- await self.connection.connect(self._settings.ip_settings)
-
- self._connected = True
+ try:
+ await self.connection.close()
+ except Exception:
+ pass # Ignore close errors, connection may already be closed
+
+ try:
+ await self.connection.connect(self._settings.ip_settings)
+ self._connected = True
+ except Exception:
+ logger.exception(
+ "Failed to reconnect to %s", self._settings.ip_settings
+ )This also requires importing import logging
logger = logging.getLogger(__name__)🤖 Prompt for AI Agents |
||
|
|
||
| async def close(self) -> None: | ||
| await self.connection.close() | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| from .controller_api import ControllerAPI as ControllerAPI | ||
| from .transport import Transport as Transport | ||
|
|
||
| try: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure connection state is cleared even when
close()fails unexpectedly.If
connection.close()raises anything other thanConnectionResetError,self.__connectionis never reset. That can leave a stale connection handle and interfere with reconnect behavior.Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents