.. _mutex: ======= Mutex ======= This project implements mutual exclusion logic that allows a resource to be locked per-user. This feature is used to block more than one user from editing the same :term:`document draft` at the same time. Note that since the lock is per user, it won't stop performing the same action in two separate browser tabs while being logged in to the same account. Single user can also hold multiple locks (to multiple documents). Resources to lock are typically identified by their UID (unique identified). The uid field is present in all models extending :class:`~megforms.base_model.BaseModel`. The lock information is stored in Redis database determined by :envvar:`REDIS_DB_MUTEX`. Locks have a timeout. The lock needs to be renewed by acquiring it again to maintain the resource lock. When the user has finished with the object, the lock can be explicitly released, or it will be release automatically after the timeout period. .. note:: Note that the locking an object does not block it from being read or written. It signals that the object is in use to other users who attempt to acquire a lock. Python code ============= .. code-block:: :emphasize-lines: 1, 4, 11 mutex = Mutex(object.uid, timedelta(minutes=1), user) try: mutex.acquire() print("You have a lock on the object for the next minute. Please Re-acquire the lock if you need to extend it, or release when no longer needed.") except ResourceLocked as e: print(f"Resource already in use by {e.user}. Please try again in 1 minute") ... # lock can be released whether it was acquired or not mutex.release() .. automodule:: utils.mutex :members: REST API ============= Lock can be acquired and released by making a ``POST`` (acquire) or ``DELETE`` (release) request to the API endpoint: :code:`/api/lock/{resource-uid}/` POST Acquires lock and responds with ``200`` status code if successful, or ``423`` if resource is already locked by another user (the response will contain the lock details). If the resource is already locked by the same user, the lock is renewed and ``200`` status code returned. .. code-block:: json :caption: Response json if lock acquisition has failed. { "message": "Resource is already in use by another user", "user_id": 1 } DELETE Releases the lock if the current user has it. Always responds with a successful ``204`` status.