exp: add a retry when removing temporary refs to avoid FileLocked errors (#10840)

This commit is contained in:
skshetry
2025-10-12 10:05:21 +05:45
committed by GitHub
parent f13ae75a45
commit 8912ca7d2b
+15 -3
View File
@@ -9,6 +9,7 @@ from enum import IntEnum
from itertools import chain from itertools import chain
from typing import TYPE_CHECKING, Any, Callable, NamedTuple, Optional, Union from typing import TYPE_CHECKING, Any, Callable, NamedTuple, Optional, Union
import funcy
from funcy import nullcontext from funcy import nullcontext
from scmrepo.exceptions import SCMError from scmrepo.exceptions import SCMError
@@ -815,11 +816,22 @@ class BaseExecutor(ABC):
@contextmanager @contextmanager
def set_temp_refs(self, scm: "Git", temp_dict: dict[str, str]): def set_temp_refs(self, scm: "Git", temp_dict: dict[str, str]):
# Retry ref set, get, and remove operations to handle transient issues during
# concurrent Git access.
# Dulwich deletes parent directories of refs if they happen to be empty after
# removing a ref, which can interfere with `set_ref` in other processes.
# `remove_ref` may also fail with a `FileLocked` error when refs are packed,
# since multiple processes might attempt to write to the same file.
retry = funcy.retry(10, errors=Exception, timeout=0.1)
set_ref = retry(scm.set_ref)
get_ref = retry(scm.get_ref)
remove_ref = retry(scm.remove_ref)
try: try:
for ref, rev in temp_dict.items(): for ref, rev in temp_dict.items():
scm.set_ref(ref, rev) set_ref(ref, rev)
yield yield
finally: finally:
for ref in temp_dict: for ref in temp_dict:
if scm.get_ref(ref): if get_ref(ref):
scm.remove_ref(ref) remove_ref(ref)