Skip to content

feat: add FirestoreSessionService for serverless session persistence#104

Closed
anmolg1997 wants to merge 1 commit intogoogle:mainfrom
anmolg1997:feat/firestore-session-service
Closed

feat: add FirestoreSessionService for serverless session persistence#104
anmolg1997 wants to merge 1 commit intogoogle:mainfrom
anmolg1997:feat/firestore-session-service

Conversation

@anmolg1997
Copy link
Copy Markdown

@anmolg1997 anmolg1997 commented Mar 21, 2026

Summary

Adds a FirestoreSessionService — a BaseSessionService implementation backed by Google Cloud Firestore, providing persistent, serverless session storage for Cloud Run, Cloud Functions, and other GCP environments where managing a SQL database is undesirable.

This was originally submitted as google/adk-python#4439, where maintainer @rohityan directed it to this community repo.

Changes

  • src/google/adk_community/sessions/firestore_session_service.py — full implementation
  • tests/unittests/sessions/test_firestore_session_service.py — 19 unit tests with lightweight in-memory Firestore mock (no GCP project required)
  • src/google/adk_community/sessions/__init__.py — export FirestoreSessionService
  • pyproject.toml — add firestore optional dependency group

Design Decisions

Concern Approach
1MB doc limit Events stored in Firestore subcollections, not embedded
Race conditions App/user state updates use Firestore transactions
N+1 in list_sessions Shared app/user state fetched once outside the loop
Bulk event deletion AsyncWriteBatch in 500-doc chunks
num_recent_events Server-side limit_to_last() instead of client-side slicing
Redundant reads create_session reuses state returned from transactional updates
Optional dependency google-cloud-firestore imported at runtime with clear error message
State management Three-tier (app/user/session) matching ADK conventions, temp state filtered

Addresses Review Feedback

All issues raised by Gemini Code Assist on the original PR have been addressed:

  • High: Race conditions in create_session and append_event → Firestore transactions
  • High: N+1 query in list_sessions → single shared fetch
  • Medium: Redundant state re-fetches → reuse transaction return values
  • Medium: Client-side slicing for recent events → limit_to_last()
  • Medium: One-by-one event deletion → AsyncWriteBatch with chunking

Test Plan

  • 19 unit tests covering all CRUD operations, state management, filtering, error cases
  • All tests pass without a GCP project (in-memory mock)
  • Existing Redis tests unaffected (1 pre-existing failure in test_session_state_management on main)
  • Manual validation with a real Firestore instance

Fixes #103
Ref: google/adk-python#3776

Adds a BaseSessionService implementation backed by Google Cloud
Firestore, providing persistent, serverless session storage suitable
for Cloud Run, Cloud Functions, and other GCP environments.

Key design decisions:
- Events stored in Firestore subcollections to avoid 1MB doc limit
- Three-tier state management (app/user/session) matching ADK conventions
- Atomic state updates via Firestore transactions (race-condition safe)
- Batch writes for bulk event deletion (500-doc chunks)
- Server-side query limits via limit_to_last() for num_recent_events
- google-cloud-firestore as an optional dependency

Includes 19 unit tests with a lightweight in-memory Firestore mock.

Fixes google#103
Ref: google/adk-python#3776, google/adk-python#4439
await self._update_user_state_transactional(
app_name, user_id, deltas["user"]
)
if deltas["session"]:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Consider moving the session state update into a transaction, similar to how _update_app_state_transactional is implemented, to avoid potential race condition.

@DeanChensj
Copy link
Copy Markdown
Collaborator

Please also fix the test failures

ScottMansfield added a commit to ScottMansfield/adk-python that referenced this pull request Apr 9, 2026
copybara-service bot pushed a commit to google/adk-python that referenced this pull request Apr 14, 2026
END_PUBLIC

Merge #5088

Adding support for Firestore for both session and memory storage.

This started by copying the Firestore support from the Java ADK into the Python ADK and also takes inspiration from @anmolg1997's PR google/adk-python-community#104. It does things differently from both.

Firestore contains a hierarchical set of data for sessions:
```
  Hierarchy for sessions:
  adk-session
  ↳ <app name>
    ↳ users
      ↳ <user ID>
        ↳ sessions
          ↳ <session ID>
            ↳ events
              ↳ <event ID>

  Hierarchy for shared App/User state configurations:
  app_states
  ↳ <app name>

  user_states
  ↳ <app name>
    ↳ users
      ↳ <user ID>

  Hierarchy for memory:
  memories
  ↳ <memory ID>
```

The firestore memory service creates a top-level collection that hold indexed memories when sessions are added.

### Link to Issue or Description of Change

This is from an existing customer request for firestore support.

### Testing Plan

**Unit Tests:**

- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.

```
$ pytest tests/unittests/integrations/firestore/
===================================== test session starts ======================================
platform darwin -- Python 3.11.14, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/scottmansfield/projects/adk-python
configfile: pyproject.toml
plugins: mock-3.15.1, xdist-3.8.0, langsmith-0.7.23, asyncio-1.3.0, anyio-4.13.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
collected 29 items

tests/unittests/integrations/firestore/test_firestore_memory_service.py .............     [ 44%]
tests/unittests/integrations/firestore/test_firestore_session_service.py ................ [100%]

======================================= warnings summary =======================================
src/google/adk/features/_feature_decorator.py:72
  /Users/scottmansfield/projects/adk-python/src/google/adk/features/_feature_decorator.py:72: UserWarning: [EXPERIMENTAL] feature FeatureName.PLUGGABLE_AUTH is enabled.
    check_feature_enabled()

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ 29 passed, 1 warning in 1.44s =================================
```

**Manual End-to-End (E2E) Tests:**

I created a demo app locally to test the session and memory storage with a real firebase instance. It successfully records sessions and memories, verified by manually checking the cloud console.

Memory did require an index, which will be created by the user the first time the memory session is used. Firestore has a specific deep link that it will create to give the exact index needed. After that, memory worked fine.

### Checklist

- [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly in hard-to-understand areas.
- [x] I have added tests that prove my fix is effective or that my feature works.
- [x] New and existing unit tests pass locally with my changes.
- [x] I have manually tested my changes end-to-end.
- [x] Any dependent changes have been merged and published in downstream modules.

COPYBARA_INTEGRATE_REVIEW=#5088 from ScottMansfield:feat/firestore 99efca5
PiperOrigin-RevId: 899328760
@anmolg1997
Copy link
Copy Markdown
Author

Hey @DeanChensj — noticed that Firestore session (and memory) support landed in core adk-python via google/adk-python#5088, which covers the same ground as this PR and then some.

Given that, I think this PR can be closed. Happy that the original design decisions here (subcollection-based events, transactional state updates, batch deletes) helped inform the final implementation.

Thanks for the review and approval — appreciate the feedback throughout the process. Closing this one out.

@anmolg1997 anmolg1997 closed this Apr 15, 2026
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.

feat: add FirestoreSessionService for serverless session persistence

2 participants