Oslo Concurrency Library
The oslo.concurrency library provides utilities for safely running multi-thread and multi-process applications using locking mechanisms, as well as for running external processes. It is a core component of the OpenStack Oslo project, which generally follows a six-month release cadence for major OpenStack releases.
Warnings
- breaking Older `oslo` libraries, including `oslo.concurrency`, deprecated and then removed the use of the `oslo` namespace package. Direct imports like `from oslo_concurrency import lockutils` are now required instead of older patterns that might have relied on a top-level `oslo` package structure.
- gotcha When using inter-process locks (`external=True` in `lockutils.synchronized`), a `lock_path` *must* be configured. This directory is used to store lock files and needs to be accessible and writable by the processes requiring synchronization. For security, it should ideally only be writable by the user running those processes. If not set, `oslo.concurrency` will raise an error or behave unexpectedly.
- gotcha While `oslo.concurrency` provides tools for safe concurrency, be aware of how other libraries handle concurrency. For example, `oslo.messaging` connections are explicitly noted as *not* concurrency safe and should not be shared between threads/greenthreads for both reading and writing, which can lead to eventlet complaints if not handled with separate connections for different operations.
Install
-
pip install oslo-concurrency
Imports
- lockutils
from oslo_concurrency import lockutils
- processutils
from oslo_concurrency import processutils
Quickstart
import os
from oslo_concurrency import lockutils
# For inter-process locking, a lock_path must be configured.
# For this example, we'll use a temporary directory.
# In a real application, this should be a secure, dedicated directory.
lock_dir = os.environ.get('OSLO_LOCK_PATH', '/tmp/oslo_locks')
os.makedirs(lock_dir, exist_ok=True)
# Configure oslo.concurrency to use the lock path
# This is typically done via oslo.config in a real OpenStack project,
# but we can set it directly for a quick example.
lockutils.set_defaults(lock_path=lock_dir)
@lockutils.synchronized('my-resource', external=True)
def my_locked_function(worker_id):
print(f"Worker {worker_id} acquired the lock.")
# Simulate some work
import time
time.sleep(0.5)
print(f"Worker {worker_id} released the lock.")
if __name__ == '__main__':
# Example of calling the locked function from multiple 'processes'
# In a real scenario, these would be separate processes.
print("Attempting to call my_locked_function from multiple 'workers'...")
for i in range(3):
my_locked_function(f"SimulatedWorker-{i}")
# Clean up the lock directory (optional for demo)
try:
os.rmdir(lock_dir)
except OSError:
# Directory might not be empty if locks were created
pass