From de160a4f053c79eb8393429a5be7c5dfba8fe43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Cruz?= Date: Mon, 15 Jul 2024 16:14:30 +0100 Subject: [PATCH] Add a default timeout for filelock (#2391) File lock operations did not have an associated timeout, which could present problems when trying to debug an issue since nothing would be logged if we could not acquire the lock and would wait forever. --- src/huggingface_hub/constants.py | 3 +++ src/huggingface_hub/utils/_fixes.py | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/huggingface_hub/constants.py b/src/huggingface_hub/constants.py index 4e999af621..53a6699cef 100644 --- a/src/huggingface_hub/constants.py +++ b/src/huggingface_hub/constants.py @@ -49,6 +49,9 @@ def _as_int(value: Optional[str]) -> Optional[int]: SAFETENSORS_INDEX_FILE = "model.safetensors.index.json" SAFETENSORS_MAX_HEADER_LENGTH = 25_000_000 +# Timeout of aquiring file lock and logging the attempt +FILELOCK_LOG_EVERY_SECONDS = 10 + # Git-related constants DEFAULT_REVISION = "main" diff --git a/src/huggingface_hub/utils/_fixes.py b/src/huggingface_hub/utils/_fixes.py index 28810dd705..3c9cce121e 100644 --- a/src/huggingface_hub/utils/_fixes.py +++ b/src/huggingface_hub/utils/_fixes.py @@ -18,8 +18,13 @@ from typing import Callable, Generator, Optional, Union import yaml -from filelock import BaseFileLock, FileLock +from filelock import BaseFileLock, FileLock, Timeout +from .. import constants +from . import logging + + +logger = logging.get_logger(__name__) # Wrap `yaml.dump` to set `allow_unicode=True` by default. # @@ -80,8 +85,14 @@ def _set_write_permission_and_retry(func, path, excinfo): @contextlib.contextmanager def WeakFileLock(lock_file: Union[str, Path]) -> Generator[BaseFileLock, None, None]: """A filelock that won't raise an exception if release fails.""" - lock = FileLock(lock_file) - lock.acquire() + lock = FileLock(lock_file, timeout=constants.FILELOCK_LOG_EVERY_SECONDS) + while True: + try: + lock.acquire() + except Timeout: + logger.info("still waiting to acquire lock on %s", lock_file) + else: + break yield lock