Skip to content

feat(persistence): add embedded seekDB support - #1293

Open
Evenss wants to merge 8 commits into
oceanbase:masterfrom
Evenss:master
Open

feat(persistence): add embedded seekDB support#1293
Evenss wants to merge 8 commits into
oceanbase:masterfrom
Evenss:master

Conversation

@Evenss

@Evenss Evenss commented Aug 20, 2026

Copy link
Copy Markdown
Member

Which issue or RFC does this PR close?

None

Rationale for this change

PowerContext currently supports SQLite and externally managed OceanBase deployments. This PR adds an optional embedded seekDB backend for users who need OceanBase-compatible persistence without running a separate database server.

The integration uses pylibseekdb only to manage the embedded database lifecycle, while reusing the existing OceanBase-compatible persistence, full-text search, and vector search paths.

What changes are included in this PR?

  • Add an optional powercontext[seekdb] extra with pylibseekdb.
  • Introduce SeekDBConfig and SeekDBProfile.
  • Start and stop the embedded seekDB instance together with the PowerContext runtime.
  • Connect to the local seekDB instance through its asynchronous MySQL Unix socket.
  • Reuse the existing OceanBase-compatible full-text and vector index implementations.
  • Add seekdb to the runtime database discriminator and persistence composition.
  • Disable session autocommit to preserve SQLAlchemy transaction behavior.
  • Add a seekDB-specific SQLAlchemy close path to avoid socket reset errors during graceful shutdown.
  • Add cancellation-safe startup cleanup and close the SQLAlchemy connection pool before stopping the embedded instance.
  • Support POWERCONTEXT_SERVER_DATABASE_KIND=seekdb.
  • Use the Server data directory's seekdb subdirectory when DATABASE_PATH is omitted or blank.
  • Support custom seekDB paths and database names.
  • Extend the real-experience E2E harness to discover, count, and purge seekDB-backed scopes.
  • Add Server settings coverage for default, blank, and custom seekDB paths.
  • Update .env.example with an opt-in embedded seekDB configuration example.
  • Update uv.lock with the optional seekDB dependency.

Are there any user-facing changes?

Yes. This PR adds a new opt-in persistence backend.

Install PowerContext with embedded seekDB support:

pip install "powercontext[server,seekdb]"

Configure the Server:

POWERCONTEXT_SERVER_DATABASE_KIND=seekdb

# Optional. When omitted, the Server uses the seekdb subdirectory
# under its data directory, such as $POWERCONTEXT_HOME/seekdb.
POWERCONTEXT_SERVER_DATABASE_PATH=.powercontext/seekdb

The seekDB database name defaults to test.

This is not a breaking change:

  • SQLite remains the default database.
  • Existing SQLite and OceanBase behavior is unchanged.
  • pylibseekdb is not installed by the default Server extra.
  • The native seekDB binding is loaded only when kind=seekdb is selected.
  • Settings parsing does not create the seekDB directory or start an embedded instance.

Embedded seekDB currently requires a supported Linux or macOS pylibseekdb wheel. Windows users can continue using SQLite or OceanBase, but embedded seekDB is not currently available on Windows.

How was this change tested?

  • uv lock --check: passed.
  • Ruff checks on the changed Python sources and focused tests: passed.
  • Type checking: passed.
  • git diff --check: passed.
  • Targeted Server database settings tests: 7 passed.
  • Manually started PowerContext with an embedded seekDB data directory.
  • Verified /health/live returned a healthy status.
  • Verified /health/ready reported both the runtime and database as ready.
  • Verified database schema initialization through the existing persistence path.
  • Verified graceful Ctrl+C shutdown exited with code 0.
  • Verified shutdown produced no ConnectionResetError, SQLAlchemy close warning, or traceback.

AI usage statement

OpenAI Codex (GPT-5.6) was used to assist with implementation, debugging, code review, test execution, and drafting this PR.

await create_tables(connection, tables)
yield profile
finally:
await database.close()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we make shutdown cancellation-safe here? If database.close() is cancelled while it is waiting for an active transaction, its close state is reset, but this outer finally still calls instance.close(). I reproduced this with pylibseekdb==1.3.0.post4: hold a transaction open, start __aexit__, and cancel it once the database enters _closing. The active connection then fails with OperationalError 2013 (Lost connection to MySQL server). This can abort an in-flight write during shutdown. Please shield and await the database close before closing the seekDB instance, then re-raise the cancellation. A regression test with a held transaction would be useful.

Comment thread pyproject.toml
"pyobvector>=0.2.28,<0.3",
"sqlalchemy[asyncio]>=2,<3",
]
seekdb = [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This extra also changes the root package metadata recorded in e2e/bub/uv.lock, but that lockfile was not regenerated. On this head, uvx --from uv==0.10.12 uv lock --project e2e/bub --locked exits with The lockfile needs to be updated; the same command passes on the base commit. Please regenerate and commit e2e/bub/uv.lock. It may also be worth making the E2E validation run the locked check, since the current sync step can update the file silently.

password=None if password_value is None else str(password_value),
host=host,
port=None if port_value is None else int(cast(int | str, port_value)),
database=config.database,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How is a non-default database supposed to be created? With a fresh embedded path and database="custom", this connection fails with OperationalError 1049: Unknown database 'custom'. The new settings test only checks parsing, so it does not catch this. Please either create the requested database before opening the main engine, or document and restrict this setting to an existing database and cover that behavior with a real open test.

Comment thread .env.example
# POWERCONTEXT_SERVER_DATABASE_KIND=oceanbase
# POWERCONTEXT_SERVER_DATABASE_URL=mysql+aoceanbase://user:password@host:2881/powercontext?charset=utf8mb4

# To use embedded seekDB instead, install powercontext[server,seekdb] and replace the SQLite database values.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we add a short section to the user-facing docs showing the complete setup for embedded seekDB? This is an optional backend, and right now the only guidance is this .env.example comment. Please include the install command, supported platforms, the required environment variables, and a start/verification example. Without that, users can switch DATABASE_KIND and only discover at runtime that the seekDB extra is missing.

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