Add managed redis config value tool and use it for scan interlock settings#959
Add managed redis config value tool and use it for scan interlock settings#959d-perl wants to merge 7 commits into
Conversation
112815d to
648dbb0
Compare
648dbb0 to
b81e21c
Compare
b81e21c to
e334fa4
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
e334fa4 to
25c0b6f
Compare
There was a problem hiding this comment.
The current version crashes the bec-scan-server, I made sure to flush redis, install all packages again in env, and upon restarting server. How you were able to get it running locally during development? Am I missing some steps?
Error:
| 2026-06-16 12:16:32 | bec_lib.bec_service | [INFO] | Connecting to Redis server at localhost:6379
ScanServer | 2026-06-16 12:16:35 | bec_lib.bec_service | [INFO] | Waiting for DeviceServer.
ScanServer | 2026-06-16 12:16:35 | bec_lib.bec_service | [SUCCESS] | DeviceServer is running.
ScanServer | 2026-06-16 12:16:35 | bec_lib.devicemanager | [WARNING] | No config available.
ScanServer | 2026-06-16 12:16:35 | bec_lib.devicemanager | [INFO] | Adding new devices:
ScanServer | 2026-06-16 12:16:35 | bec_server.scan_server.scan_queue | [INFO] | New scan queue:
ScanServer | 2026-06-16 12:16:35 | bec_server.scan_server.scan_queue | [INFO] |
primary queue / ScanQueueStatus.RUNNING
┏━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ queue_id ┃ scan_id ┃ is_scan ┃ type ┃ scan_number ┃ IQ status ┃
┡━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━┩
└──────────┴─────────┴─────────┴──────┴─────────────┴───────────┘
ScanServer | 2026-06-16 12:16:35 | bec_server.procedures.manager | [SUCCESS] | Initialising ProcedureManager, using worker type 'SubProcessWorker'...
ScanServer | 2026-06-16 12:16:35 | bec_server.procedures.manager | [SUCCESS] | Done initialising procedure manager.
ScanServer | 2026-06-16 12:16:35 | bec_server.procedures.manager | [SUCCESS] | Initialising ActorManager, using worker type 'ActorProcedureWorker'...
ScanServer | 2026-06-16 12:16:35 | bec_server.procedures.manager | [SUCCESS] | Done initialising procedure manager.
ScanServer | 2026-06-16 12:16:35 | bec_lib.bec_service | [INFO] | Connecting to Redis server at localhost:6379
Traceback (most recent call last):
File "/Users/janwyzula/miniforge3/envs/bec_312/bin/bec-scan-server", line 8, in <module>
sys.exit(main())
^^^^^^
File "/Users/janwyzula/PSI/bec/bec_server/bec_server/scan_server/cli/launch.py", line 21, in main
bec_server = scan_server.ScanServer(config=config, connector_cls=RedisConnector)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_server/bec_server/scan_server/scan_server.py", line 45, in __init__
self._start_actor_managers()
File "/Users/janwyzula/PSI/bec/bec_server/bec_server/scan_server/scan_server.py", line 91, in _start_actor_managers
self.builtin_actor_manager = BuiltinActorManager(self.bootstrap_server)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_server/bec_server/actors/builtin_actor_manager.py", line 48, in __init__
self._client.start()
File "/Users/janwyzula/PSI/bec/bec_lib/bec_lib/client.py", line 219, in start
self.builtin_actors = BuiltinActorHli(self)
^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_lib/bec_lib/builtin_actor_hli.py", line 113, in __init__
self.scan_interlock = ScanInterlockHli(self._client, self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_lib/bec_lib/builtin_actor_hli.py", line 27, in __init__
self._enabled = RedisConfigValue(
^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_lib/bec_lib/config_values.py", line 31, in __init__
self._config = self._fetch()
^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_lib/bec_lib/config_values.py", line 42, in _fetch
existing = self._connector.xread(self._ep, id="+", count=1)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_lib/bec_lib/redis_connector.py", line 184, in wrapper
return func(*tuple(arg), **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/PSI/bec/bec_lib/bec_lib/redis_connector.py", line 1476, in xread
msg = client.xread({topic: id}, count=count, block=block)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/commands/core.py", line 4001, in xread
return self.execute_command("XREAD", *pieces, keys=keys)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/client.py", line 621, in execute_command
return self._execute_command(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/client.py", line 632, in _execute_command
return conn.retry.call_with_retry(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/retry.py", line 105, in call_with_retry
return do()
^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/client.py", line 633, in <lambda>
lambda: self._send_command_parse_response(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/client.py", line 604, in _send_command_parse_response
return self.parse_response(conn, command_name, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/client.py", line 651, in parse_response
response = connection.read_response()
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/janwyzula/miniforge3/envs/bec_312/lib/python3.12/site-packages/redis/connection.py", line 672, in read_response
raise response
redis.exceptions.ResponseError: Invalid stream ID specified as stream command argumentStates and interlock on main before switching branches:
• default@bec [1/1] ❯❯ bec.builtin_actors.scan_interlock.states_watched
Out[1]: {}
• default@bec [2/1] ❯❯ bec.builtin_actors.scan_interlock.enabled
Out[2]: False
• default@bec [3/1] ❯❯ bec.beamline_states.show_all()
Beamline States
┏━━━━━━┳━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━┓
┃ Name ┃ Type ┃ Parameters ┃ Status ┃ Label ┃
┃ ┃ ┃ ┃ ┃ ┃
┡━━━━━━╇━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━┩
└──────┴──────┴────────────┴────────┴───────┘
• default@bec [4/1] ❯❯There was a problem hiding this comment.
Pull request overview
This PR introduces a typed, subscribable Redis-backed configuration abstraction (RedisConfigValue) and migrates scan interlock enablement + interlock-trigger behavior (restart/pause/do-nothing) to use it, including updates to server-side actor management and client HLI.
Changes:
- Added
ManagedConfigMessagemessage pattern plus new scan-interlock config messages/endpoints. - Implemented
RedisConfigValueto read/write STREAM-based config values and notify subscribers. - Updated scan interlock actor + builtin actor manager + HLI and expanded unit/e2e test coverage around the new config-driven behavior.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| bec_server/tests/tests_scan_server/test_builtin_actor_manager.py | Updates tests for builtin actor manager behavior after moving to config-value-driven enablement and new handler names. |
| bec_server/bec_server/actors/scan_interlock.py | Uses a Redis-managed config value to decide whether to restart (or pause) scans when the interlock triggers. |
| bec_server/bec_server/actors/builtin_actor_manager.py | Switches scan interlock lifecycle management to a Redis-managed enabled flag and renames the beamline-state handler. |
| bec_lib/tests/test_managed_config_values.py | Adds unit tests validating RedisConfigValue behavior and type constraints. |
| bec_lib/bec_lib/tests/utils.py | Adds a wait_until helper used by the new managed-config tests. |
| bec_lib/bec_lib/redis_connector.py | Minor readability fix in stream subscription tracking (topic not in ...). |
| bec_lib/bec_lib/messages.py | Introduces ManagedConfigMessage, BoolConfigDefaultFalse, and scan-interlock trigger setting enum/message. |
| bec_lib/bec_lib/endpoints.py | Adds scan interlock config endpoints and adjusts typing of endpoint message type var. |
| bec_lib/bec_lib/config_values.py | New RedisConfigValue implementation (Redis-backed, subscribable config value). |
| bec_lib/bec_lib/client.py | Moves builtin_actors initialization into start() so the connector is available. |
| bec_lib/bec_lib/builtin_actor_hli.py | Migrates scan interlock HLI to read/write Redis-managed enable + trigger-setting config values. |
| bec_ipython_client/tests/end-2-end/test_actors_e2e.py | Extends e2e actor test to set/verify scan interlock trigger setting via the HLI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
pretty weird, it works on my machine both at work and home, as well as with redis in CI. it should work without flushing redis or any of that. maybe some weird redis for macos issue? anyway, I changed one of the lines that looked like it could be responsible, would you try again? |
wyzula-jan
left a comment
There was a problem hiding this comment.
First part, some minor comments to the code, but I noticed bug when ScanInterlock forgets the trigger settings -> showed online
wyzula-jan
left a comment
There was a problem hiding this comment.
another minor finding
c5ce8c9 to
b298331
Compare
b298331 to
69fb523
Compare
8c4430a to
0cb8821
Compare
0cb8821 to
cc114e0
Compare
RedisConfigValuewhich associates to a config value in Redis which can be subscribed to, and infers the type of the config value from the endpoint and message type