feat: add configs for database connection (#128)
This commit is contained in:
parent
49e233cdb7
commit
33fac2c5e2
4 changed files with 87 additions and 9 deletions
|
|
@ -73,6 +73,16 @@ ENV_LAZY_RERANKER = "HINDSIGHT_API_LAZY_RERANKER"
|
|||
# Database migrations
|
||||
ENV_RUN_MIGRATIONS_ON_STARTUP = "HINDSIGHT_API_RUN_MIGRATIONS_ON_STARTUP"
|
||||
|
||||
# Database connection pool
|
||||
ENV_DB_POOL_MIN_SIZE = "HINDSIGHT_API_DB_POOL_MIN_SIZE"
|
||||
ENV_DB_POOL_MAX_SIZE = "HINDSIGHT_API_DB_POOL_MAX_SIZE"
|
||||
ENV_DB_COMMAND_TIMEOUT = "HINDSIGHT_API_DB_COMMAND_TIMEOUT"
|
||||
ENV_DB_ACQUIRE_TIMEOUT = "HINDSIGHT_API_DB_ACQUIRE_TIMEOUT"
|
||||
|
||||
# Background task processing
|
||||
ENV_TASK_BATCH_SIZE = "HINDSIGHT_API_TASK_BATCH_SIZE"
|
||||
ENV_TASK_BATCH_INTERVAL = "HINDSIGHT_API_TASK_BATCH_INTERVAL"
|
||||
|
||||
# Default values
|
||||
DEFAULT_DATABASE_URL = "pg0"
|
||||
DEFAULT_LLM_PROVIDER = "openai"
|
||||
|
|
@ -109,6 +119,16 @@ DEFAULT_RETAIN_CHUNK_SIZE = 3000 # Max chars per chunk for fact extraction
|
|||
# Database migrations
|
||||
DEFAULT_RUN_MIGRATIONS_ON_STARTUP = True
|
||||
|
||||
# Database connection pool
|
||||
DEFAULT_DB_POOL_MIN_SIZE = 5
|
||||
DEFAULT_DB_POOL_MAX_SIZE = 100
|
||||
DEFAULT_DB_COMMAND_TIMEOUT = 60 # seconds
|
||||
DEFAULT_DB_ACQUIRE_TIMEOUT = 30 # seconds
|
||||
|
||||
# Background task processing
|
||||
DEFAULT_TASK_BATCH_SIZE = 10
|
||||
DEFAULT_TASK_BATCH_INTERVAL = 1.0 # seconds
|
||||
|
||||
# Default MCP tool descriptions (can be customized via env vars)
|
||||
DEFAULT_MCP_RETAIN_DESCRIPTION = """Store important information to long-term memory.
|
||||
|
||||
|
|
@ -193,6 +213,16 @@ class HindsightConfig:
|
|||
# Database migrations
|
||||
run_migrations_on_startup: bool
|
||||
|
||||
# Database connection pool
|
||||
db_pool_min_size: int
|
||||
db_pool_max_size: int
|
||||
db_command_timeout: int
|
||||
db_acquire_timeout: int
|
||||
|
||||
# Background task processing
|
||||
task_batch_size: int
|
||||
task_batch_interval: float
|
||||
|
||||
@classmethod
|
||||
def from_env(cls) -> "HindsightConfig":
|
||||
"""Create configuration from environment variables."""
|
||||
|
|
@ -245,6 +275,14 @@ class HindsightConfig:
|
|||
retain_chunk_size=int(os.getenv(ENV_RETAIN_CHUNK_SIZE, str(DEFAULT_RETAIN_CHUNK_SIZE))),
|
||||
# Database migrations
|
||||
run_migrations_on_startup=os.getenv(ENV_RUN_MIGRATIONS_ON_STARTUP, "true").lower() == "true",
|
||||
# Database connection pool
|
||||
db_pool_min_size=int(os.getenv(ENV_DB_POOL_MIN_SIZE, str(DEFAULT_DB_POOL_MIN_SIZE))),
|
||||
db_pool_max_size=int(os.getenv(ENV_DB_POOL_MAX_SIZE, str(DEFAULT_DB_POOL_MAX_SIZE))),
|
||||
db_command_timeout=int(os.getenv(ENV_DB_COMMAND_TIMEOUT, str(DEFAULT_DB_COMMAND_TIMEOUT))),
|
||||
db_acquire_timeout=int(os.getenv(ENV_DB_ACQUIRE_TIMEOUT, str(DEFAULT_DB_ACQUIRE_TIMEOUT))),
|
||||
# Background task processing
|
||||
task_batch_size=int(os.getenv(ENV_TASK_BATCH_SIZE, str(DEFAULT_TASK_BATCH_SIZE))),
|
||||
task_batch_interval=float(os.getenv(ENV_TASK_BATCH_INTERVAL, str(DEFAULT_TASK_BATCH_INTERVAL))),
|
||||
)
|
||||
|
||||
def get_llm_base_url(self) -> str:
|
||||
|
|
|
|||
|
|
@ -215,9 +215,13 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
embeddings: Embeddings | None = None,
|
||||
cross_encoder: CrossEncoderModel | None = None,
|
||||
query_analyzer: QueryAnalyzer | None = None,
|
||||
pool_min_size: int = 5,
|
||||
pool_max_size: int = 100,
|
||||
pool_min_size: int | None = None,
|
||||
pool_max_size: int | None = None,
|
||||
db_command_timeout: int | None = None,
|
||||
db_acquire_timeout: int | None = None,
|
||||
task_backend: TaskBackend | None = None,
|
||||
task_batch_size: int | None = None,
|
||||
task_batch_interval: float | None = None,
|
||||
run_migrations: bool = True,
|
||||
operation_validator: "OperationValidatorExtension | None" = None,
|
||||
tenant_extension: "TenantExtension | None" = None,
|
||||
|
|
@ -248,9 +252,13 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
embeddings: Embeddings implementation. If not provided, created from env vars.
|
||||
cross_encoder: Cross-encoder model. If not provided, created from env vars.
|
||||
query_analyzer: Query analyzer implementation. If not provided, uses DateparserQueryAnalyzer.
|
||||
pool_min_size: Minimum number of connections in the pool (default: 5)
|
||||
pool_max_size: Maximum number of connections in the pool (default: 100)
|
||||
pool_min_size: Minimum number of connections in the pool. Defaults to HINDSIGHT_API_DB_POOL_MIN_SIZE.
|
||||
pool_max_size: Maximum number of connections in the pool. Defaults to HINDSIGHT_API_DB_POOL_MAX_SIZE.
|
||||
db_command_timeout: PostgreSQL command timeout in seconds. Defaults to HINDSIGHT_API_DB_COMMAND_TIMEOUT.
|
||||
db_acquire_timeout: Connection acquisition timeout in seconds. Defaults to HINDSIGHT_API_DB_ACQUIRE_TIMEOUT.
|
||||
task_backend: Custom task backend. If not provided, uses AsyncIOQueueBackend.
|
||||
task_batch_size: Background task batch size. Defaults to HINDSIGHT_API_TASK_BATCH_SIZE.
|
||||
task_batch_interval: Background task batch interval in seconds. Defaults to HINDSIGHT_API_TASK_BATCH_INTERVAL.
|
||||
run_migrations: Whether to run database migrations during initialize(). Default: True
|
||||
operation_validator: Optional extension to validate operations before execution.
|
||||
If provided, retain/recall/reflect operations will be validated.
|
||||
|
|
@ -306,8 +314,10 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
# Connection pool (will be created in initialize())
|
||||
self._pool = None
|
||||
self._initialized = False
|
||||
self._pool_min_size = pool_min_size
|
||||
self._pool_max_size = pool_max_size
|
||||
self._pool_min_size = pool_min_size if pool_min_size is not None else config.db_pool_min_size
|
||||
self._pool_max_size = pool_max_size if pool_max_size is not None else config.db_pool_max_size
|
||||
self._db_command_timeout = db_command_timeout if db_command_timeout is not None else config.db_command_timeout
|
||||
self._db_acquire_timeout = db_acquire_timeout if db_acquire_timeout is not None else config.db_acquire_timeout
|
||||
self._run_migrations = run_migrations
|
||||
|
||||
# Initialize entity resolver (will be created in initialize())
|
||||
|
|
@ -386,7 +396,11 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
self._cross_encoder_reranker = CrossEncoderReranker(cross_encoder=cross_encoder)
|
||||
|
||||
# Initialize task backend
|
||||
self._task_backend = task_backend or AsyncIOQueueBackend(batch_size=100, batch_interval=1.0)
|
||||
_task_batch_size = task_batch_size if task_batch_size is not None else config.task_batch_size
|
||||
_task_batch_interval = task_batch_interval if task_batch_interval is not None else config.task_batch_interval
|
||||
self._task_backend = task_backend or AsyncIOQueueBackend(
|
||||
batch_size=_task_batch_size, batch_interval=_task_batch_interval
|
||||
)
|
||||
|
||||
# Backpressure mechanism: limit concurrent searches to prevent overwhelming the database
|
||||
# Limit concurrent searches to prevent connection pool exhaustion
|
||||
|
|
@ -731,9 +745,9 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
self.db_url,
|
||||
min_size=self._pool_min_size,
|
||||
max_size=self._pool_max_size,
|
||||
command_timeout=60,
|
||||
command_timeout=self._db_command_timeout,
|
||||
statement_cache_size=0, # Disable prepared statement cache
|
||||
timeout=30, # Connection acquisition timeout (seconds)
|
||||
timeout=self._db_acquire_timeout, # Connection acquisition timeout (seconds)
|
||||
)
|
||||
|
||||
# Initialize entity resolver with pool
|
||||
|
|
|
|||
|
|
@ -197,6 +197,12 @@ def main():
|
|||
skip_llm_verification=config.skip_llm_verification,
|
||||
lazy_reranker=config.lazy_reranker,
|
||||
run_migrations_on_startup=config.run_migrations_on_startup,
|
||||
db_pool_min_size=config.db_pool_min_size,
|
||||
db_pool_max_size=config.db_pool_max_size,
|
||||
db_command_timeout=config.db_command_timeout,
|
||||
db_acquire_timeout=config.db_acquire_timeout,
|
||||
task_batch_size=config.task_batch_size,
|
||||
task_batch_interval=config.task_batch_interval,
|
||||
)
|
||||
config.configure_logging()
|
||||
if not args.daemon:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,17 @@ The API service handles all memory operations (retain, recall, reflect).
|
|||
|
||||
If not provided, the server uses embedded `pg0` — convenient for development but not recommended for production.
|
||||
|
||||
### Database Connection Pool
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `HINDSIGHT_API_DB_POOL_MIN_SIZE` | Minimum connections in the pool | `5` |
|
||||
| `HINDSIGHT_API_DB_POOL_MAX_SIZE` | Maximum connections in the pool | `100` |
|
||||
| `HINDSIGHT_API_DB_COMMAND_TIMEOUT` | PostgreSQL command timeout in seconds | `60` |
|
||||
| `HINDSIGHT_API_DB_ACQUIRE_TIMEOUT` | Connection acquisition timeout in seconds | `30` |
|
||||
|
||||
For high-concurrency workloads, increase `DB_POOL_MAX_SIZE`. Each concurrent recall/think operation can use 2-4 connections.
|
||||
|
||||
To run migrations manually (e.g., before starting the API), use the admin CLI:
|
||||
|
||||
```bash
|
||||
|
|
@ -266,6 +277,15 @@ Configuration for the local MCP server (`hindsight-local-mcp` command).
|
|||
export HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take, including tool calls and decisions made."
|
||||
```
|
||||
|
||||
### Background Tasks
|
||||
|
||||
Controls background task processing for async operations like opinion formation and entity observations.
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `HINDSIGHT_API_TASK_BATCH_SIZE` | Max tasks to process in one batch | `10` |
|
||||
| `HINDSIGHT_API_TASK_BATCH_INTERVAL` | Interval between batch processing in seconds | `1.0` |
|
||||
|
||||
### Performance Optimization
|
||||
|
||||
| Variable | Description | Default |
|
||||
|
|
|
|||
Loading…
Reference in a new issue