bluesky_queueserver_api.zmq.REManagerAPI.lock

REManagerAPI.lock(lock_key=None, *, environment=None, queue=None, note=None, user=None)

Lock RE Manager with a lock key. The lock may prevent other users (or clients) from modifying the environment, starting plans or tasks or editing the queue. The API is intented to supports the scenarios when a beamline scientist needs to lock RE Manager with a unique code before entering the hutch to change samples or make adjustments and then safely run a series of calibration or testing plans without interference from automated agents or remote users. A remote operators may still control locked RE Manager if the beamline scientist provides them with the lock key.

The lock is not intended for access control. The read-only API are not affected by the lock, therefore all monitoring client applications are expected to remain functional after the lock is applied. The lock does not influence internal operation of the manager, e.g. the running queue will continue running and has to be explicitly stopped if needed. Restarting RE Manager does not remove the lock. The locked manager must be unlocked with REManagerAPI.unlock() API using the valid lock key (normal operation), an optional emergency lock key (in case the lock key is lost) or qserver-clear-lock CLI tool (last resort, requires restarting RE Manager).

The lock can be set using current lock key (set using REManagerAPI.lock_key property) or passed to the API directly using the lock_key parameter. The key passed as a parameter always overrides the current lock key. The operator may still execute locked API using a valid lock key. If access to locked API is enabled (REManagerAPI.enable_locked_api is True), then the current lock key is automatically passed with each lockable API. The key passed with lock_api parameter overrides the current key and is always passed with the API call. This mechanism allows to set the key only once (RM.lock_key="some-lock-key") and use it to lock and unlock the manager and access the locked API if needed. The lock_key API parameter is used in applications where setting a global lock key is not desirable (e.g. in the implementation of multi-user HTTP Server).

The API parameters allow to choose between locking the environment, the queue or both. The environment is locked by setting environment=True or calling REManagerAPI.lock_environment() and affects the following API:

  • REManagerAPI.environment_open()

  • REManagerAPI.environment_close()

  • REManagerAPI.environment_destroy()

  • REManagerAPI.environment_update()

  • REManagerAPI.queue_start()

  • REManagerAPI.queue_stop()

  • REManagerAPI.queue_stop_cancel()

  • REManagerAPI.item_execute()

  • REManagerAPI.re_pause()

  • REManagerAPI.re_resume()

  • REManagerAPI.re_stop()

  • REManagerAPI.re_abort()

  • REManagerAPI.re_halt()

  • REManagerAPI.kernel_interrupt()

  • REManagerAPI.script_upload()

  • REManagerAPI.function_execute()

The queue is locked by setting queue=True or calling REManagerAPI.lock_queue() and affects the following API:

  • REManagerAPI.queue_mode_set()

  • REManagerAPI.queue_autostart()

  • REManagerAPI.item_add()

  • REManagerAPI.item_add_batch()

  • REManagerAPI.item_update()

  • REManagerAPI.item_remove()

  • REManagerAPI.item_remove_batch()

  • REManagerAPI.item_move()

  • REManagerAPI.item_move_batch()

  • REManagerAPI.queue_clear()

  • REManagerAPI.history_clear()

  • REManagerAPI.permissions_reload()

  • REManagerAPI.permissions_set()

The environment and the queue may be locked by setting environment=True, queue=True or calling REManagerAPI.lock_all() and affects the API from both groups.

The additional parameters include the name of the user (user) who is locking RE Manager and an optional note (message) passed to other users (note), which explains the reason why the manager is locked. The user name and the note is returned by lock_info API and included in the ‘Invalid lock key’ error messages.

The API may be called if RE Manager is already locked to change the lock options or the note. In this case, the lock key passed with the request must match the key used to lock the manager. There is no API that allows to change the lock without unlocking the manager.

Parameters:
lock_key: str (optional)

The lock key is an arbitrary non-empty string. Users/clients are expected to keep the key used to lock RE Manager and use it to unlock the manager or make API requests. If the lock key is lost by accident, then RE Manager may be unlocked using the emergency lock key. If lock_key is not set, then the current key (REManagerAPI.lock_key property) is used. If neither keys are set, then RuntimeError (lock key is not set) is raised.

environment: boolean (optional)

Enable lock for the API that control RE Worker environment. The request fails if both environment and queue are missing or False. Default: False.

queue: boolean (optinal)

Enable lock for the API that control the queue. The request fails if both environment and queue are missing or False. Default: False.

user: str (optional)

Name of the user who submits the request. The user name is returned as part of lock_info and included in error messages. If the parameter is missing or None, then REManagerAPI.user is passed with the API call. Default: None.

note: str or None (optional)

A text message to other users that explains the reason why RE Manager is locked. The note is returned as part of lock_info and included in error messages. If the value is None, then no message submitted. Default: None.

Returns:
response: dict

Dictionary keys:

  • success: boolean - success of the request.

  • msg: str - error message in case the request is rejected by RE Manager or operation failed.

  • lock_info: dict - dictionary containing the information on the status of the lock. The dictionary is also returned by REManagerAPI.lock_info() and includes the following fields:

    • environment: boolean - indicates if the RE Worker environment is locked.

    • queue: boolean - indicates if the queue is locked.

    • user: str or None - the name of the user who locked RE Manager, None if the lock is not set.

    • note: str or None - the text note left by the user who locked RE Manager, None if the lock is not set.

    • time: float or None - timestamp (time when RE Manager was locked), None if the lock is not set.

    • time_str: str - human-readable representation of the timestamp, empty string if the lock is not set.

    • emergency_lock_key_is_set: boolean - indicates if the optional emergency lock key is set.

  • lock_info_uid: str UID of lock_info. The UID is also returned in RE Manager status and could be monitored to detect updates of lock_info.

Raises:
RequestTimeoutError, RequestFailedError, HTTPRequestError, HTTPClientError, HTTPServerError

All exceptions raised by send_request API.

RuntimeError

The lock key (lock_key parameter) is not passed and the current lock key (REManagerAPI.lock_key) is not set.

Examples

Setting and using current lock key (sync and async API).

# Set current lock key. The key may be any string.
#   The default lock key persists between sessions.
RM.lock_key = RM.get_default_lock_key()

RM.lock(environment=True, note="Some informative message ...")
# await RM.lock(environment=True, note="Some informative message ...")

response = RM.lock_info()
# response = await RM.lock_info()
print(response["lock_info"])

RM.lock_queue(note="Another message ...")
# await RM.lock_queue(note="Another message ...")

RM.lock_environment(note="Different message ...")
# await RM.lock_environment(note="Different message ...")

RM.lock_all(note="Any useful message ...")
# await RM.lock_environment(note="Any useful message ...")

try:
    RM.environment_open()  # API call fails because the environment is locked.
    # await RM.environment_open()
except Exception as ex:
    print(f"API call failed: {ex}")

# If locked API are enabled, then the current lock key is sent with each API request.
RM.enable_locked_api = True

RM.environment_open()  # API call is expected to succeed.
# await RM.environment_open()

RM.unlock()
# await RM.unlock()

Explicitly passing the lock key as a parameter (sync and async API).

# Select the lock key. The key may be any string.
#   The default lock key persists between sessions.
lock_key = "some-arbitrary-string-key"
# lock_key = RM.get_default_lock_key()

RM.lock(lock_key=lock_key, environment=True, note="Some informative message ...")
# await RM.lock(lock_key=lock_key, environment=True, note="Some informative message ...")

response = RM.lock_info()
# response = await RM.lock_info()
print(response["lock_info"])

RM.lock_queue(lock_key=lock_key, note="Another message ...")
# await RM.lock_queue(lock_key=lock_key, note="Another message ...")

RM.lock_environment(lock_key=lock_key, note="Different message ...")
# await RM.lock_environment(lock_key=lock_key, note="Different message ...")

RM.lock_all(lock_key=lock_key, note="Any useful message ...")
# await RM.lock_environment(lock_key=lock_key, note="Any useful message ...")

try:
    RM.environment_open()  # API call fails because the environment is locked.
    # await RM.environment_open()
except Exception as ex:
    print(f"API call failed: {ex}")

RM.environment_open(lock_key=lock_key)  # API call is expected to succeed.
# await RM.environment_open(lock_key=lock_key)

RM.unlock(lock_key=lock_key)
# await RM.unlock(lock_key=lock_key)