From 608f4ec0d59fd4b648efa06e1b0ba3beaae71e72 Mon Sep 17 00:00:00 2001 From: Richard Bowman Date: Tue, 28 Apr 2026 12:11:06 +0100 Subject: [PATCH 1/3] Enable global locking. This commit: * switches to the LabThings branch * enables locking when config files are loaded * Updates jogging so jog moves aren't subject to the lock, but the jog loop is. --- src/openflexure_microscope_server/server/__init__.py | 7 +++++++ src/openflexure_microscope_server/things/stage/__init__.py | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/openflexure_microscope_server/server/__init__.py b/src/openflexure_microscope_server/server/__init__.py index 546f7118..494f940d 100644 --- a/src/openflexure_microscope_server/server/__init__.py +++ b/src/openflexure_microscope_server/server/__init__.py @@ -190,4 +190,11 @@ def _full_config_from_args(args: Namespace) -> ThingServerConfig: ) patched_config = load_patched_config(args.config) + if "enable_global_lock" not in patched_config: + patched_config["enable_global_lock"] = True + if patched_config["enable_global_lock"] is not True: + raise ValueError( + "OpenFlexure Microscope Server requires `enable_global_lock` to be `true`, " + "and it was set to another value in the configuration file." + ) return ThingServerConfig(**patched_config) diff --git a/src/openflexure_microscope_server/things/stage/__init__.py b/src/openflexure_microscope_server/things/stage/__init__.py index e5b0b72b..f9c9973f 100644 --- a/src/openflexure_microscope_server/things/stage/__init__.py +++ b/src/openflexure_microscope_server/things/stage/__init__.py @@ -404,7 +404,7 @@ class BaseStage(lt.Thing): "StageThings must define their own _estimate_move_duration method" ) - @lt.action + @lt.action(use_global_lock=False) def jog(self, stop: bool = False, **kwargs: int) -> None: """Make a relative move that may be interrupted by a future ``jog``. @@ -471,7 +471,7 @@ class BaseStage(lt.Thing): command: Optional[JogCommand] = first_command # prevent others using the stage while jogging. - with self._hardware_lock: + with self._thing_server_interface.hold_global_lock(True), self._hardware_lock: while command is not None: if command.displacement is not None: self._hardware_start_move_relative(command.displacement) From b6f4c9972e5c98414885c5ab9f11cde5045e6db8 Mon Sep 17 00:00:00 2001 From: Richard Bowman Date: Tue, 28 Apr 2026 12:13:26 +0100 Subject: [PATCH 2/3] Exempt stitching and downloading scans from the global lock. --- src/openflexure_microscope_server/things/smart_scan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openflexure_microscope_server/things/smart_scan.py b/src/openflexure_microscope_server/things/smart_scan.py index 25b0a60b..3f2c6dfb 100644 --- a/src/openflexure_microscope_server/things/smart_scan.py +++ b/src/openflexure_microscope_server/things/smart_scan.py @@ -692,7 +692,7 @@ class SmartScanThing(OFMThing): raise HTTPException(404, "File not found") return FileResponse(preview_path) - @lt.action + @lt.action(use_global_lock=False) def stitch_scan(self, scan_name: str) -> None: """Generate a stitched image based on stage position metadata.""" scan_data = self._scan_dir_manager.get_scan_data(scan_name) @@ -720,7 +720,7 @@ class SmartScanThing(OFMThing): except SubprocessError as e: self.logger.error(f"Stitching failed: {e}", exc_info=e) - @lt.action + @lt.action(use_global_lock=False) def download_zip( self, scan_name: str, @@ -732,7 +732,7 @@ class SmartScanThing(OFMThing): zip_fname = self._scan_dir_manager.zip_scan(scan_name, final_version=True) return ZipBlob.from_file(zip_fname) - @lt.action + @lt.action(use_global_lock=False) def stitch_all_scans(self) -> None: """Check the list of scans, and stitch any that don't have a DZI associated with it. From a47a56986888838d2e18a5087cfeb466b39c6b3e Mon Sep 17 00:00:00 2001 From: Richard Bowman Date: Tue, 5 May 2026 22:21:06 +0100 Subject: [PATCH 3/3] Update usage of hold_global_lock The argument to `ThingServerInterface.hold_global_lock` was changed, so that `True` is now the default behaviour. This commit updates that in the one place where it's used. --- src/openflexure_microscope_server/things/stage/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openflexure_microscope_server/things/stage/__init__.py b/src/openflexure_microscope_server/things/stage/__init__.py index f9c9973f..a42190c6 100644 --- a/src/openflexure_microscope_server/things/stage/__init__.py +++ b/src/openflexure_microscope_server/things/stage/__init__.py @@ -471,7 +471,7 @@ class BaseStage(lt.Thing): command: Optional[JogCommand] = first_command # prevent others using the stage while jogging. - with self._thing_server_interface.hold_global_lock(True), self._hardware_lock: + with self._thing_server_interface.hold_global_lock(), self._hardware_lock: while command is not None: if command.displacement is not None: self._hardware_start_move_relative(command.displacement)