seitime-frappe/frappe/utils/file_lock.py
Gavin D'souza fe26c542b7 refactor: Move before/after tasks as hooks
Moved before/after tasks in Requests as hooks for:
- monitor
- rate_limiter
- recorder

Moved before/after tasks in Jobs as hooks for:
- monitor
- releasing document locks
2023-02-15 15:30:02 +05:30

70 lines
1.6 KiB
Python

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
"""Utils for inter-process synchronization using file-locks.
This file implements a "weak" form lock which is not suitable for synchroniztion. This is only used
for document locking for queue_action.
Use `frappe.utils.synchroniztion.filelock` for process synchroniztion.
"""
import os
from time import time
import frappe
from frappe.utils import get_site_path, touch_file
LOCKS_DIR = "locks"
class LockTimeoutError(Exception):
pass
def create_lock(name):
"""Creates a file in the /locks folder by the given name.
Note: This is a "weak lock" and is prone to race conditions. Do not use this lock for small
sections of code that execute immediately.
This is primarily use for locking documents for background submission.
"""
lock_path = get_lock_path(name)
if not check_lock(lock_path):
return touch_file(lock_path)
else:
return False
def lock_exists(name):
"""Returns True if lock of the given name exists"""
return os.path.exists(get_lock_path(name))
def check_lock(path, timeout=600):
if not os.path.exists(path):
return False
if time() - os.path.getmtime(path) > timeout:
raise LockTimeoutError(path)
return True
def delete_lock(name):
lock_path = get_lock_path(name)
try:
os.remove(lock_path)
except OSError:
pass
return True
def get_lock_path(name):
name = name.lower()
lock_path = get_site_path(LOCKS_DIR, name + ".lock")
return lock_path
def release_document_locks():
"""Unlocks all documents that were locked by the current context."""
for doc in frappe.local.locked_documents:
doc.unlock()