Skip to content

Commit

Permalink
Add lock to prevent concurrent attempts to open/close the dome
Browse files Browse the repository at this point in the history
  • Loading branch information
albireox committed Jan 21, 2025
1 parent 30f1085 commit 5052f3a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Added try-excepts and timeouts to the different tasks in the Overwatcher shutdown routine to ensure that the dome closure is always attempted.
* Move `DomeHelper.startup()` to `Overwatcher.startup()` and clean up observer code.
* Retry emitting Overwatcher heartbeats.
* Add additional checks to prevent concurrent attempts to open/close the dome.

### 🔧 Fixed

Expand Down
90 changes: 51 additions & 39 deletions src/gort/devices/enclosure.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ def __init__(self, gort: Gort, name: str, actor: str, **kwargs):
self.lights = Lights(self)
self.e_stops = E_Stops(self)

self._dome_lock = asyncio.Lock()

async def restart(self):
"""Restarts the ``lvmecp`` deployment."""

Expand All @@ -174,8 +176,8 @@ async def status(self, get_registers: bool = False):
async def allowed_to_move(self):
"""Checks if the dome is allowed to move."""

dome: ActorReply = await self.actor.commands.dome.commands.status(timeout=5)
labels = dome.get("dome_status_labels", default="").split(",")
status: ActorReply = await self.actor.commands.dome.commands.status(timeout=5)
labels = status.get("dome_status_labels", default="").split(",")

if "DRIVE_ERROR" in labels:
return False
Expand Down Expand Up @@ -235,7 +237,7 @@ async def _check_dome(self):
)
else:
raise GortEnclosureError(
"Dome found in error state. Cannot move the dome.",
"Not allowed to move the dome.",
error_code=ErrorCode.ENCLOSURE_ERROR,
)

Expand All @@ -250,18 +252,23 @@ async def open(self, park_telescopes: bool = True):
"""

await self._check_dome()
async with self._dome_lock:
if await self.is_open():
self.write_to_log("Dome is already open.", level="info")
return

await self._check_dome()

if park_telescopes:
await self._park_telescopes()
if park_telescopes:
await asyncio.wait_for(self._park_telescopes(), timeout=120)

self.write_to_log("Opening the enclosure ...", level="info")
await self.gort.notify_event(Event.DOME_OPENING)
self.write_to_log("Opening the enclosure ...", level="info")
await self.gort.notify_event(Event.DOME_OPENING)

await self.actor.commands.dome.commands.open()
await self.actor.commands.dome.commands.open()

self.write_to_log("Enclosure is now open.", level="info")
await self.gort.notify_event(Event.DOME_OPEN)
self.write_to_log("Enclosure is now open.", level="info")
await self.gort.notify_event(Event.DOME_OPEN)

async def close(
self,
Expand Down Expand Up @@ -293,36 +300,41 @@ async def close(
if reset_lockout:
await self.actor.commands.dome.commands.reset()

await self._check_dome()

if park_telescopes:
try:
await asyncio.wait_for(self._park_telescopes(), timeout=120)
except Exception as err:
self.write_to_log(
f"Failed parking the telescopes: {err}",
"error",
exc_info=err,
)
if force is False:
raise GortEnclosureError(
"Not closing without knowing where the telescopes are. "
"If you really need to close call again with "
"park_telescopes=False and force=True.",
async with self._dome_lock:
if not force and await self.is_closed():
self.write_to_log("Dome is already closed.", level="info")
return

await self._check_dome()

if park_telescopes:
try:
await asyncio.wait_for(self._park_telescopes(), timeout=120)
except Exception as err:
self.write_to_log(
f"Failed parking the telescopes: {err}",
"error",
exc_info=err,
)
else:
self.write_to_log("Closing dome because force=True", "warning")

self.write_to_log("Closing the dome ...", level="info")
await self.gort.notify_event(Event.DOME_CLOSING)

await self.actor.commands.dome.commands.close(
force=force,
overcurrent=(mode == "overcurrent"),
)
if force is False:
raise GortEnclosureError(
"Not closing without knowing where the telescopes are. "
"If you really need to close call again with "
"park_telescopes=False and force=True.",
)
else:
self.write_to_log("Closing dome because force=True", "warning")

self.write_to_log("Closing the dome ...", level="info")
await self.gort.notify_event(Event.DOME_CLOSING)

await self.actor.commands.dome.commands.close(
force=force,
overcurrent=(mode == "overcurrent"),
)

self.write_to_log("Enclosure is now closed.", level="info")
await self.gort.notify_event(Event.DOME_CLOSED)
self.write_to_log("Enclosure is now closed.", level="info")
await self.gort.notify_event(Event.DOME_CLOSED)

async def is_open(self):
"""Returns :obj:`True` if the enclosure is open."""
Expand Down

0 comments on commit 5052f3a

Please sign in to comment.