Skip lock acquisition in CrewTrainingHandler.load when file is missing (#5935)

Every agent kickoff calls _use_trained_data, which calls
CrewTrainingHandler(...).load(). Since #4827 wrapped load() in store_lock,
that means every kickoff acquires the cross-process (Redis-backed when
REDIS_URL is set) lock even on deployments that never train and have no
trained-agents file on disk.

Move the missing/empty-file short-circuit above store_lock so the lock is
only acquired when there is actually a file to read. save() and the real
read remain locked.
This commit is contained in:
Vini Brasil
2026-05-26 12:52:31 -03:00
committed by GitHub
parent bad64b1ee6
commit 32f5e74449
3 changed files with 43 additions and 12 deletions

View File

@@ -167,17 +167,12 @@ class PickleHandler:
Returns:
The data loaded from the file.
"""
with store_lock(f"file:{os.path.realpath(self.file_path)}"):
if (
not os.path.exists(self.file_path)
or os.path.getsize(self.file_path) == 0
):
return {}
if not os.path.exists(self.file_path):
return {}
with open(self.file_path, "rb") as file:
try:
with store_lock(f"file:{os.path.realpath(self.file_path)}"):
try:
with open(self.file_path, "rb") as file:
return pickle.load(file) # noqa: S301
except EOFError:
return {}
except Exception:
raise
except (FileNotFoundError, EOFError):
return {}

View File

@@ -1083,6 +1083,21 @@ def test_agent_use_trained_data_honors_env_var(crew_training_handler, monkeypatc
)
def test_agent_use_trained_data_skips_load_when_file_missing(tmp_path, monkeypatch):
monkeypatch.setenv(
"CREWAI_TRAINED_AGENTS_FILE", str(tmp_path / "does_not_exist.pkl")
)
agent = Agent(role="researcher", goal="test goal", backstory="test backstory")
with patch(
"crewai.utilities.file_handler.store_lock",
side_effect=AssertionError("kickoff acquired lock with no trained-agents file"),
):
result = agent._use_trained_data(task_prompt="What is 1 + 1?")
assert result == "What is 1 + 1?"
def test_agent_max_retry_limit():
agent = Agent(
role="test role",

View File

@@ -1,6 +1,7 @@
import os
import tempfile
import unittest
from unittest.mock import patch
from crewai.utilities.training_handler import CrewTrainingHandler
@@ -53,3 +54,23 @@ class InternalCrewTrainingHandler(unittest.TestCase):
# Assert that the new agent and data are appended correctly
data = self.handler.load()
assert data[agent_id][train_iteration] == new_data
def test_load_missing_file_does_not_acquire_lock(self):
handler = CrewTrainingHandler(self.temp_file.name + ".missing")
with patch(
"crewai.utilities.file_handler.store_lock",
side_effect=AssertionError("load() acquired lock for missing file"),
):
assert handler.load() == {}
def test_load_acquires_lock_for_zero_size_file(self):
# Empty file mimics a concurrent save() mid-truncation (open "wb").
assert os.path.getsize(self.temp_file.name) == 0
with patch(
"crewai.utilities.file_handler.store_lock",
side_effect=AssertionError("load() short-circuited on size 0"),
):
with self.assertRaises(AssertionError):
self.handler.load()