{"id":2954,"library":"flufl-lock","title":"NFS-safe File Locking","description":"The flufl.lock library provides an NFS-safe, file-based locking algorithm for POSIX and Windows systems, heavily influenced by the GNU/Linux open(2) manpage's O_EXCL option. It aims to prevent race conditions on NFS file systems by using atomic file operations with robust timeouts and lock-breaking capabilities. Currently at version 9.0.0, the library is under active development with regular updates and maintenance releases.","status":"active","version":"9.0.0","language":"en","source_language":"en","source_url":"https://gitlab.com/warsaw/flufl.lock","tags":["lock","locking","NFS","file-locking","concurrency","synchronization"],"install":[{"cmd":"pip install flufl.lock","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"Lock","correct":"from flufl.lock import Lock"},{"symbol":"AlreadyLockedError","correct":"from flufl.lock import AlreadyLockedError"},{"symbol":"NotLockedError","correct":"from flufl.lock import NotLockedError"}],"quickstart":{"code":"import tempfile\nimport os\nfrom flufl.lock import Lock, AlreadyLockedError\n\n# Create a temporary file to use as the lock file\n# In a real application, use a persistent path accessible to all processes\nwith tempfile.NamedTemporaryFile(delete=False) as tmp_lock_file:\n    lock_file_path = tmp_lock_file.name\n\ntry:\n    # Acquire the lock using a context manager for automatic release\n    # default lifetime is 15 seconds\n    with Lock(lock_file_path) as lock:\n        print(f\"Lock acquired on {lock_file_path}\")\n        print(f\"Is locked: {lock.is_locked}\")\n        print(\"Performing some locked operation...\")\n        # Simulate another process trying to acquire the same lock\n        try:\n            with Lock(lock_file_path, default_timeout=1) as other_lock:\n                print(\"This should not be reached if the lock is held.\")\n        except AlreadyLockedError:\n            print(\"Another process correctly detected the lock is held.\")\n        # The lock is automatically released when exiting the 'with' block\n    print(\"Lock released.\")\n\n    # Acquire and release manually\n    lock = Lock(lock_file_path)\n    lock.lock()\n    print(\"Lock acquired manually.\")\n    lock.refresh()\n    print(\"Lock refreshed (lifetime extended).\")\n    lock.unlock()\n    print(\"Lock released manually.\")\n\nfinally:\n    # Clean up the temporary lock file\n    if os.path.exists(lock_file_path):\n        os.remove(lock_file_path)\n    # The library might create a claim file; ensure it's also cleaned.\n    # For this simple example, we assume lock_file_path is sufficient.\n","lang":"python","description":"This quickstart demonstrates basic lock acquisition and release using both context managers and explicit `lock()`/`unlock()` calls. It also shows how to handle `AlreadyLockedError` and refresh a lock. A temporary file is used for demonstration purposes; in production, you would use a stable, shared file path."},"warnings":[{"fix":"Carefully consider the maximum expected duration of your critical section and set the `lifetime` parameter accordingly. Use `lock.refresh()` to extend the lock's lifetime if operations take longer than anticipated.","message":"Choosing an appropriate 'lifetime' for a lock is crucial. If too long, stale locks (from crashed processes) will block others excessively. If too short, other processes might prematurely break an active lock, leading to data corruption.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure all systems accessing the shared lock file have their clocks synchronized, e.g., using NTP.","message":"For distributed (NFS) environments, proper clock synchronization between participating machines is essential. Inaccurate clocks can lead to incorrect lock expiration calculations, causing stale locks to persist or active locks to be prematurely broken.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Upgrade your Python environment to 3.10 or newer (for flufl.lock 9.x) if you need to use the latest version of the library. Check the changelog for specific version requirements if targeting older flufl.lock releases.","message":"Version 9.0.0 removed support for Python 3.9. Previous major versions also dropped support for older Python versions (e.g., 8.0 dropped 3.7).","severity":"breaking","affected_versions":"9.0.0+"},{"fix":"If encountering `DistributionNotFound` issues, particularly with tools that rely on older setuptools mechanisms, consider pinning `flufl.lock < 8.0` or checking the downstream application's compatibility matrix.","message":"Some applications (e.g., DVC) have reported `pkg_resources.DistributionNotFound` errors when using `flufl.lock` version 8.0 or newer due to potential changes in how its metadata is packaged or resolved by downstream tools.","severity":"gotcha","affected_versions":"8.0+"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}