Skip to content

Fix/falkordb group id race condition#1305

Open
kraft87 wants to merge 2 commits intogetzep:mainfrom
kraft87:fix/falkordb-group-id-race-condition
Open

Fix/falkordb group id race condition#1305
kraft87 wants to merge 2 commits intogetzep:mainfrom
kraft87:fix/falkordb-group-id-race-condition

Conversation

@kraft87
Copy link
Copy Markdown

@kraft87 kraft87 commented Mar 7, 2026

Summary

Fix a race condition where FalkorDB driver state was mutated in-place when group_id differed from the current database, causing concurrent calls to corrupt each other's database context.

Type of Change

  • Bug fix
  • Documentation/Tests

Objective

When add_episode or add_episode_bulk was called with a group_id different from the FalkorDB driver's current database, the code mutated shared state:

self.driver = self.driver.clone(database=group_id)
self.clients.driver = self.driver

Under concurrent calls (e.g., asyncio.gather with different tenants), coroutines would overwrite each other's driver, writing data to the wrong database.

Changes

Core fix -- driver isolation (graphiti_core/graphiti.py):

  • Removed the in-place self.driver / self.clients.driver mutation from both add_episode and add_episode_bulk
  • Both methods now accept an optional driver kwarg, create a local clients = self.clients.model_copy(update={'driver': driver}), and thread that through all internal calls
  • All internal helpers (_process_episode_data, _extract_and_dedupe_nodes_and_edges, _resolve_nodes_and_edges_bulk, _get_or_create_saga, _extract_and_resolve_edges) updated to accept and propagate driver
  • Every self.driver / self.clients reference in these methods replaced with the local driver / clients

Decorator-based group_id handling (graphiti_core/decorators.py):

  • Added @handle_single_group_id -- detects FalkorDB provider, clones the driver scoped to the group_id, calls ensure_database_initialized(), and injects as driver kwarg. The original self.clients.driver is never touched.
  • Updated @handle_multiple_group_ids -- now calls ensure_database_initialized() on each cloned driver

FalkorDB driver (graphiti_core/driver/falkordb_driver.py):

  • clone() now uses copy.copy(self) instead of constructing a new FalkorDriver, avoiding re-running __init__ (which schedules index builds, creates new operation objects, etc.)
  • Added _initialized_databases: set[str] -- shared by reference across all clones via shallow copy
  • Added ensure_database_initialized() -- idempotent guard that calls build_indices_and_constraints() only once per database across all clones

Base driver (graphiti_core/driver/driver.py):

  • Added no-op ensure_database_initialized() to GraphDriver base class

Build/test infra:

  • Makefile: Added test-integration target, added DISABLE_NEO4J=1 and -n auto to unit test command, increased Docker wait timeout to 300s for WSL
  • pytest.ini: Added norecursedirs = mcp_server server to prevent collecting tests from sub-projects
  • Deleted empty mcp_server/tests/__init__.py

Formatting (auto-applied by make format):

  • Minor reformatting in edges.py, nodes.py, community_operations.py, edge_operations.py, gliner2_client.py, gliner2_neo4j.py (line length, quote style)

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • All existing tests pass
File Tests Type
tests/test_decorators.py 17 Unit -- covers get_parameter_position, @handle_multiple_group_ids, @handle_single_group_id
tests/test_group_id_isolation.py 9 unit + 2 integration Verifies original driver is never mutated, cloned drivers are injected, concurrent calls are isolated, add_episode_bulk propagates driver
tests/driver/test_falkordb_driver.py 7 unit + 1 integration clone(), ensure_database_initialized(), shared _initialized_databases

Checklist

  • Code follows project style guidelines (make lint passes)
  • Self-review completed
  • Documentation updated where necessary
  • No secrets or sensitive information committed

kraft87 added 2 commits March 7, 2026 09:13
- Added integration tests for FalkorDriver.clone() and ensure_database_initialized() to verify correct behavior with multiple group IDs.
- Introduced new test cases for handling group ID isolation to prevent driver mutation during concurrent operations.
- Updated Makefile to include integration tests and adjusted test command to run with pytest-xdist for parallel execution.
- Refactored logging statements for better readability in edges and nodes embedding processes.
- Added new test suite for decorators to ensure proper functionality of group ID handling.
- Removed empty test initialization file and updated pytest configuration to exclude certain directories.
@danielchalef
Copy link
Copy Markdown
Member

danielchalef commented Mar 7, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@kraft87
Copy link
Copy Markdown
Author

kraft87 commented Mar 7, 2026

I have read the CLA Document and I hereby sign the CLA

danielchalef added a commit that referenced this pull request Mar 7, 2026
ehfazrezwan added a commit to ehfazrezwan/neuralscape that referenced this pull request Apr 2, 2026
feafc42 Bump the uv group across 2 directories with 2 updates (getzep#1363)
c4e6923 Upstream Zep internal improvements (getzep#1361)
e88c09c @VictorECDSA has signed the CLA in getzep#1356
91fe7e0 @majiayu000 has signed the CLA in getzep#1351
c52786d @dudo has signed the CLA in getzep#1350
d631437 @Ker102 has signed the CLA in getzep#1339
73cff2c @chengjon has signed the CLA in getzep#1340
8c61763 @rhlsthrm has signed the CLA in getzep#1335
e6424ba @pratyush618 has signed the CLA in getzep#1332
6f05647 @bsolomon1124 has signed the CLA in getzep#1330
10d9139 @spencer2211 has signed the CLA in getzep#1326
1ca1468 Add hiring promotion section to README (getzep#1323)
19e44a9 Bump mcp-server to 1.0.2 and require graphiti-core>=0.28.2 (getzep#1317)
77b1609 Bump graphiti-core version to 0.28.2 (getzep#1315)
7d65d5e Harden search filters against Cypher injection (getzep#1312)
b10b488 Restore README title and subtitle (getzep#1314)
a9065fa Refresh README content and fix image refs (getzep#1313)
5a334ec @lvca has signed the CLA in getzep#1310
45c8040 @jawherkh has signed the CLA in getzep#1309
9eb2c9e @kraft87 has signed the CLA in getzep#1305
334c8fa @adsharma has signed the CLA in getzep#1296
b6f9d87 @StephenBadger has signed the CLA in getzep#1295
4b91076 feat: Add GLiNER2 hybrid LLM client (getzep#1284)
db54ce0 chore: update Docker images to graphiti-core 0.28.1 (getzep#1292)
edc71e8 @devmao has signed the CLA in getzep#1289
b4ddc55 @carlos-alm has signed the CLA in getzep#1288
aa8e81e @giulio-leone has signed the CLA in getzep#1280
6fdb352 @aelhajj has signed the CLA in getzep#1281
2099603 @avianion has signed the CLA in getzep#1278
9eb59f7 @themavik has signed the CLA in getzep#1214
98f5b5f fix: replace edge name with uuid in debug log (getzep#1261)
510bd50 @hanxiao has signed the CLA in getzep#1257
17a8ea9 @sprotasovitsky has signed the CLA in getzep#1254
9d509a2 @Yifan-233-max has signed the CLA in getzep#1245
ef52a2a chore: regenerate lockfiles to drop diskcache (getzep#1244)
7605303 chore: bump version to 0.28.1 (getzep#1243)
bde2f79 fix: replace diskcache with sqlite-based cache to resolve CVE (getzep#1238)

git-subtree-dir: graphiti
git-subtree-split: feafc42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants