Skip to content

Bug: DatabaseSessionService Race Condition in Table Creation and PostgreSQL Timezone Incompatibility #4445

@JoaoCampista

Description

@JoaoCampista

Bug: DatabaseSessionService Race Condition in Table Creation and PostgreSQL Timezone Incompatibility

🔴 Required Information

Describe the Bug:
There are two issues identified when using DatabaseSessionService with PostgreSQL (via asyncpg):

  1. Race Condition in _prepare_tables: When multiple concurrent requests hit the server at startup, _prepare_tables can return early because _db_schema_version is set by one request, even if _tables_created is still false and tables are not yet fully created. This leads to UndefinedTableError because the table sessions does not exist when a query is executed.
  2. Timezone Incompatibility: The PreciseTimestamp type uses DateTime (which is timezone-naive by default in SQLAlchemy for PostgreSQL), but the service attempts to insert timezone-aware datetimes (datetime.now(timezone.utc)). asyncpg strictly enforces timezone correctness, leading to DataError: invalid input for query argument ... (can't subtract offset-naive and offset-aware datetimes).

Steps to Reproduce:

  1. Install google-adk==1.24.1 and asyncpg.
  2. Configure DatabaseSessionService with a PostgreSQL URL (postgresql+asyncpg://...).
  3. Start a FastAPI application that uses DatabaseSessionService.
  4. Send concurrent requests to an endpoint that uses sessions (e.g., list_sessions or creating a session) immediately upon startup.

Expected Behavior:

  1. _prepare_tables should block until tables are confirmed created, regardless of _db_schema_version being set.
  2. PreciseTimestamp should define DateTime(timezone=True) to create TIMESTAMP WITH TIME ZONE columns in PostgreSQL, allowing storage of timezone-aware datetimes.

Observed Behavior:

  1. sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.ProgrammingError: <class 'asyncpg.exceptions.UndefinedTableError'>: relation "sessions" does not exist
  2. sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.Error: <class 'asyncpg.exceptions.DataError'>: invalid input for query argument $5: datetime.datetime(...) (can't subtract offset-naive and offset-aware datetimes)

Environment Details:

  • ADK Library Version: 1.24.1
  • Desktop OS: Linux
  • Python Version: 3.14.2

Model Information:

  • Are you using LiteLLM: N/A
  • Which model is being used: N/A

🟡 Optional Information

Regression:
Unknown.

Logs:

sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.ProgrammingError: <class 'asyncpg.exceptions.UndefinedTableError'>: relation "sessions" does not exist

...

sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.Error: <class 'asyncpg.exceptions.DataError'>: invalid input for query argument $5: datetime.datetime(2026, 2, 10, 21, 55, 5... (can't subtract offset-naive and offset-aware datetimes)

Additional Context:
We have patched the library locally to fix these issues.

Proposed Fix:

In google/adk/sessions/database_session_service.py:

    async with self._db_schema_lock:
      # Double-check after acquiring the lock
      if self._db_schema_version is None:  # CHANGED: Only check if None
        try:
          async with self.db_engine.connect() as conn:
            self._db_schema_version = await conn.run_sync(
                _schema_check_utils.get_db_schema_version_from_connection
            )
        except Exception as e:
          logger.error("Failed to inspect database tables: %s", e)
          raise

    # Check if tables are created and create them if not
    if self._tables_created:
      return

    # ... rest of the function ...

In google/adk/sessions/schemas/shared.py:

class PreciseTimestamp(TypeDecorator):
  """Represents a timestamp precise to the microsecond."""

  impl = DateTime(timezone=True)  # CHANGED: Added timezone=True
  cache_ok = True
  # ...

Metadata

Metadata

Assignees

Labels

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

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions