mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-05-16 21:53:45 +00:00
* fix: prevent concurrent subagent file write conflicts Serialize same-path str_replace operations in sandbox tools Guard AioSandbox write_file/update_file with the existing sandbox lock Add regression tests for concurrent str_replace and append races Verify with backend full tests and ruff lint checks * fix(sandbox): Fix the concurrency issue of file operations on the same path in isolated sandboxes. Ensure that different sandbox instances use independent locks for file operations on the same virtual path to avoid concurrency conflicts. Change the lock key from a single path to a composite key of (sandbox.id, path), and add tests to verify the concurrent safety of isolated sandboxes. * feat(sandbox): Extract file operation lock logic to standalone module and fix concurrency issues Extract file operation lock related logic from tools.py into a separate file_operation_lock.py module. Fix data race issues during concurrent str_replace and write_file operations.
24 lines
761 B
Python
24 lines
761 B
Python
import threading
|
|
|
|
from deerflow.sandbox.sandbox import Sandbox
|
|
|
|
_FILE_OPERATION_LOCKS: dict[tuple[str, str], threading.Lock] = {}
|
|
_FILE_OPERATION_LOCKS_GUARD = threading.Lock()
|
|
|
|
|
|
def get_file_operation_lock_key(sandbox: Sandbox, path: str) -> tuple[str, str]:
|
|
sandbox_id = getattr(sandbox, "id", None)
|
|
if not sandbox_id:
|
|
sandbox_id = f"instance:{id(sandbox)}"
|
|
return sandbox_id, path
|
|
|
|
|
|
def get_file_operation_lock(sandbox: Sandbox, path: str) -> threading.Lock:
|
|
lock_key = get_file_operation_lock_key(sandbox, path)
|
|
with _FILE_OPERATION_LOCKS_GUARD:
|
|
lock = _FILE_OPERATION_LOCKS.get(lock_key)
|
|
if lock is None:
|
|
lock = threading.Lock()
|
|
_FILE_OPERATION_LOCKS[lock_key] = lock
|
|
return lock
|