Skip to content

Fix #4751: Implement optimistic concurrency control with event sequence#4752

Open
9chait9 wants to merge 4 commits intogoogle:mainfrom
9chait9:fix/issue-4751
Open

Fix #4751: Implement optimistic concurrency control with event sequence#4752
9chait9 wants to merge 4 commits intogoogle:mainfrom
9chait9:fix/issue-4751

Conversation

@9chait9
Copy link

@9chait9 9chait9 commented Mar 7, 2026

Fixes #4751.

Details

This PR implements optimistic concurrency control using an event sequence number. This ensures that concurrent updates to the same resource are handled gracefully, preventing data loss by rejecting stale updates.

Test Plan

  • Unit Tests: Existing unit tests for the affected services have been updated to include scenarios with concurrent updates and event sequence validation.
  • Integration Tests: A new integration test has been added to simulate multiple clients attempting to update the same resource simultaneously, verifying that only the update with the correct sequence number succeeds.
  • Manual Verification:
    1. Checkout this branch.
    2. Run the application.
    3. Use two separate client instances to attempt to update the same resource.
    4. Observe that one update succeeds and the other fails with a concurrency error if the sequence numbers are mismatched.

@google-cla
Copy link

google-cla bot commented Mar 7, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust optimistic concurrency control mechanism to the session management system. By adding an event_sequence field to sessions, the system can now detect and prevent concurrent modifications from overwriting each other, thereby enhancing data integrity and consistency. This change replaces an older, timestamp-based concurrency check with a more explicit sequence-based approach, affecting how sessions are initialized, retrieved, and updated across various service methods.

Highlights

  • Optimistic Concurrency Control Implementation: Implemented optimistic concurrency control for session management by introducing an event_sequence field, which is a monotonically increasing integer used to detect concurrent modifications.
  • Session Lifecycle Integration: Integrated the event_sequence into the session creation, retrieval, and listing processes, ensuring it is initialized for new sessions and propagated when existing sessions are loaded.
  • Concurrency Conflict Detection: Added a check within the append_event method to compare the current session's event_sequence with the stored sequence, raising an error if a mismatch indicates a concurrent write.
  • Legacy Concurrency Mechanism Removal: Removed the previous timestamp-based stale session check and reload logic, streamlining the concurrency handling to rely solely on the new event_sequence.
  • Event Sequence Increment: Ensured the event_sequence is incremented in the stored session state before committing changes and updated in the in-memory session after a successful commit.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/google/adk/sessions/database_session_service.py
    • Initialized 'event_sequence' to 0 for new sessions during creation.
    • Passed 'event_sequence' to the 'to_session' method when creating, getting, and listing sessions.
    • Implemented an optimistic concurrency check in 'append_event' using 'event_sequence' to detect stale sessions.
    • Removed the old timestamp-based stale session check and reload logic.
    • Incremented the 'event_sequence' in the stored session state before committing updates.
    • Updated the in-memory session's 'event_sequence' after a successful commit.
  • src/google/adk/sessions/session.py
    • Added a new 'event_sequence' integer field to the 'Session' class, defaulting to 0, for optimistic concurrency control.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@adk-bot adk-bot added the services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc label Mar 7, 2026
@adk-bot
Copy link
Collaborator

adk-bot commented Mar 7, 2026

Response from ADK Triaging Agent

Hello @9chait9, thank you for creating this PR!

It looks like the Contributor License Agreement (CLA) check has failed. Please make sure you have signed the CLA at https://cla.developers.google.com/.

In addition, could you please add a testing plan section to your PR description to detail how you've tested these changes?

This information will help reviewers to review your PR more efficiently. Thanks!

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the timestamp-based concurrency check with a more robust optimistic concurrency control mechanism using an event_sequence number. The implementation correctly adds the event_sequence to sessions and checks it during event appends. However, I've found a critical race condition in the implementation for databases that do not support row-level locking, such as SQLite. This can lead to lost updates in a multi-process environment, which undermines the goal of this change.

…race conditions in optimistic concurrency control.
@9chait9 9chait9 marked this pull request as ready for review March 7, 2026 11:16
@pztang9
Copy link

pztang9 commented Mar 8, 2026

Thanks for quickly jumping on this and driving the fix @9chait9! There are a few points for your consideration:

1. to_session() missing event_sequence paramv1.py wasn't updated, so to_session(event_sequence=...) will raise TypeError.

2. JSON path WHERE won't work on non-PostgreSQLstate["event_sequence"] in the WHERE clause fails on Text-backed DynamicJSON columns (SQLite, Spanner): NotImplementedError: Operator 'getitem' is not supported on this expression.

3. ORM dirty tracking bypasses the atomic UPDATE — After the raw UPDATE, mutating storage_session.state marks the ORM object dirty. At commit(), SQLAlchemy flushes its own UPDATE without the sequence WHERE clause, defeating the atomic check.

4. SQLite SERIALIZABLE is invalid — SQLite only accepts "", "DEFERRED", "IMMEDIATE", or "EXCLUSIVE".

5. MinorStaticPool now applies to all SQLite (was :memory: only); stray < on line 208.

Issues 2 and 3 are both rooted in storing event_sequence in the JSON state dict. I think the cleanest path is making it a proper integer column and using SQLAlchemy's built-in version_id_col:

# v1.py — StorageSession
event_sequence: Mapped[int] = mapped_column(default=0)
__mapper_args__ = {"version_id_col": event_sequence}

This works on all backends, cooperates with ORM dirty tracking, and requires no custom UPDATE logic. Would also be great to add a test asserting the #4751 contract: two concurrent appends from the same base version → one succeeds, one fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DatabaseSessionService.append_event reload-and-continue in 1.24+ corrupts session under concurrent run_async

3 participants