Skip to content

Commit 33fac2c

Browse files
authored
feat: add configs for database connection (#128)
1 parent 49e233c commit 33fac2c

File tree

4 files changed

+87
-9
lines changed

4 files changed

+87
-9
lines changed

hindsight-api/hindsight_api/config.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@
7373
# Database migrations
7474
ENV_RUN_MIGRATIONS_ON_STARTUP = "HINDSIGHT_API_RUN_MIGRATIONS_ON_STARTUP"
7575

76+
# Database connection pool
77+
ENV_DB_POOL_MIN_SIZE = "HINDSIGHT_API_DB_POOL_MIN_SIZE"
78+
ENV_DB_POOL_MAX_SIZE = "HINDSIGHT_API_DB_POOL_MAX_SIZE"
79+
ENV_DB_COMMAND_TIMEOUT = "HINDSIGHT_API_DB_COMMAND_TIMEOUT"
80+
ENV_DB_ACQUIRE_TIMEOUT = "HINDSIGHT_API_DB_ACQUIRE_TIMEOUT"
81+
82+
# Background task processing
83+
ENV_TASK_BATCH_SIZE = "HINDSIGHT_API_TASK_BATCH_SIZE"
84+
ENV_TASK_BATCH_INTERVAL = "HINDSIGHT_API_TASK_BATCH_INTERVAL"
85+
7686
# Default values
7787
DEFAULT_DATABASE_URL = "pg0"
7888
DEFAULT_LLM_PROVIDER = "openai"
@@ -109,6 +119,16 @@
109119
# Database migrations
110120
DEFAULT_RUN_MIGRATIONS_ON_STARTUP = True
111121

122+
# Database connection pool
123+
DEFAULT_DB_POOL_MIN_SIZE = 5
124+
DEFAULT_DB_POOL_MAX_SIZE = 100
125+
DEFAULT_DB_COMMAND_TIMEOUT = 60 # seconds
126+
DEFAULT_DB_ACQUIRE_TIMEOUT = 30 # seconds
127+
128+
# Background task processing
129+
DEFAULT_TASK_BATCH_SIZE = 10
130+
DEFAULT_TASK_BATCH_INTERVAL = 1.0 # seconds
131+
112132
# Default MCP tool descriptions (can be customized via env vars)
113133
DEFAULT_MCP_RETAIN_DESCRIPTION = """Store important information to long-term memory.
114134
@@ -193,6 +213,16 @@ class HindsightConfig:
193213
# Database migrations
194214
run_migrations_on_startup: bool
195215

216+
# Database connection pool
217+
db_pool_min_size: int
218+
db_pool_max_size: int
219+
db_command_timeout: int
220+
db_acquire_timeout: int
221+
222+
# Background task processing
223+
task_batch_size: int
224+
task_batch_interval: float
225+
196226
@classmethod
197227
def from_env(cls) -> "HindsightConfig":
198228
"""Create configuration from environment variables."""
@@ -245,6 +275,14 @@ def from_env(cls) -> "HindsightConfig":
245275
retain_chunk_size=int(os.getenv(ENV_RETAIN_CHUNK_SIZE, str(DEFAULT_RETAIN_CHUNK_SIZE))),
246276
# Database migrations
247277
run_migrations_on_startup=os.getenv(ENV_RUN_MIGRATIONS_ON_STARTUP, "true").lower() == "true",
278+
# Database connection pool
279+
db_pool_min_size=int(os.getenv(ENV_DB_POOL_MIN_SIZE, str(DEFAULT_DB_POOL_MIN_SIZE))),
280+
db_pool_max_size=int(os.getenv(ENV_DB_POOL_MAX_SIZE, str(DEFAULT_DB_POOL_MAX_SIZE))),
281+
db_command_timeout=int(os.getenv(ENV_DB_COMMAND_TIMEOUT, str(DEFAULT_DB_COMMAND_TIMEOUT))),
282+
db_acquire_timeout=int(os.getenv(ENV_DB_ACQUIRE_TIMEOUT, str(DEFAULT_DB_ACQUIRE_TIMEOUT))),
283+
# Background task processing
284+
task_batch_size=int(os.getenv(ENV_TASK_BATCH_SIZE, str(DEFAULT_TASK_BATCH_SIZE))),
285+
task_batch_interval=float(os.getenv(ENV_TASK_BATCH_INTERVAL, str(DEFAULT_TASK_BATCH_INTERVAL))),
248286
)
249287

250288
def get_llm_base_url(self) -> str:

hindsight-api/hindsight_api/engine/memory_engine.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,13 @@ def __init__(
215215
embeddings: Embeddings | None = None,
216216
cross_encoder: CrossEncoderModel | None = None,
217217
query_analyzer: QueryAnalyzer | None = None,
218-
pool_min_size: int = 5,
219-
pool_max_size: int = 100,
218+
pool_min_size: int | None = None,
219+
pool_max_size: int | None = None,
220+
db_command_timeout: int | None = None,
221+
db_acquire_timeout: int | None = None,
220222
task_backend: TaskBackend | None = None,
223+
task_batch_size: int | None = None,
224+
task_batch_interval: float | None = None,
221225
run_migrations: bool = True,
222226
operation_validator: "OperationValidatorExtension | None" = None,
223227
tenant_extension: "TenantExtension | None" = None,
@@ -248,9 +252,13 @@ def __init__(
248252
embeddings: Embeddings implementation. If not provided, created from env vars.
249253
cross_encoder: Cross-encoder model. If not provided, created from env vars.
250254
query_analyzer: Query analyzer implementation. If not provided, uses DateparserQueryAnalyzer.
251-
pool_min_size: Minimum number of connections in the pool (default: 5)
252-
pool_max_size: Maximum number of connections in the pool (default: 100)
255+
pool_min_size: Minimum number of connections in the pool. Defaults to HINDSIGHT_API_DB_POOL_MIN_SIZE.
256+
pool_max_size: Maximum number of connections in the pool. Defaults to HINDSIGHT_API_DB_POOL_MAX_SIZE.
257+
db_command_timeout: PostgreSQL command timeout in seconds. Defaults to HINDSIGHT_API_DB_COMMAND_TIMEOUT.
258+
db_acquire_timeout: Connection acquisition timeout in seconds. Defaults to HINDSIGHT_API_DB_ACQUIRE_TIMEOUT.
253259
task_backend: Custom task backend. If not provided, uses AsyncIOQueueBackend.
260+
task_batch_size: Background task batch size. Defaults to HINDSIGHT_API_TASK_BATCH_SIZE.
261+
task_batch_interval: Background task batch interval in seconds. Defaults to HINDSIGHT_API_TASK_BATCH_INTERVAL.
254262
run_migrations: Whether to run database migrations during initialize(). Default: True
255263
operation_validator: Optional extension to validate operations before execution.
256264
If provided, retain/recall/reflect operations will be validated.
@@ -306,8 +314,10 @@ def __init__(
306314
# Connection pool (will be created in initialize())
307315
self._pool = None
308316
self._initialized = False
309-
self._pool_min_size = pool_min_size
310-
self._pool_max_size = pool_max_size
317+
self._pool_min_size = pool_min_size if pool_min_size is not None else config.db_pool_min_size
318+
self._pool_max_size = pool_max_size if pool_max_size is not None else config.db_pool_max_size
319+
self._db_command_timeout = db_command_timeout if db_command_timeout is not None else config.db_command_timeout
320+
self._db_acquire_timeout = db_acquire_timeout if db_acquire_timeout is not None else config.db_acquire_timeout
311321
self._run_migrations = run_migrations
312322

313323
# Initialize entity resolver (will be created in initialize())
@@ -386,7 +396,11 @@ def __init__(
386396
self._cross_encoder_reranker = CrossEncoderReranker(cross_encoder=cross_encoder)
387397

388398
# Initialize task backend
389-
self._task_backend = task_backend or AsyncIOQueueBackend(batch_size=100, batch_interval=1.0)
399+
_task_batch_size = task_batch_size if task_batch_size is not None else config.task_batch_size
400+
_task_batch_interval = task_batch_interval if task_batch_interval is not None else config.task_batch_interval
401+
self._task_backend = task_backend or AsyncIOQueueBackend(
402+
batch_size=_task_batch_size, batch_interval=_task_batch_interval
403+
)
390404

391405
# Backpressure mechanism: limit concurrent searches to prevent overwhelming the database
392406
# Limit concurrent searches to prevent connection pool exhaustion
@@ -731,9 +745,9 @@ async def verify_llm():
731745
self.db_url,
732746
min_size=self._pool_min_size,
733747
max_size=self._pool_max_size,
734-
command_timeout=60,
748+
command_timeout=self._db_command_timeout,
735749
statement_cache_size=0, # Disable prepared statement cache
736-
timeout=30, # Connection acquisition timeout (seconds)
750+
timeout=self._db_acquire_timeout, # Connection acquisition timeout (seconds)
737751
)
738752

739753
# Initialize entity resolver with pool

hindsight-api/hindsight_api/main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ def release_lock():
197197
skip_llm_verification=config.skip_llm_verification,
198198
lazy_reranker=config.lazy_reranker,
199199
run_migrations_on_startup=config.run_migrations_on_startup,
200+
db_pool_min_size=config.db_pool_min_size,
201+
db_pool_max_size=config.db_pool_max_size,
202+
db_command_timeout=config.db_command_timeout,
203+
db_acquire_timeout=config.db_acquire_timeout,
204+
task_batch_size=config.task_batch_size,
205+
task_batch_interval=config.task_batch_interval,
200206
)
201207
config.configure_logging()
202208
if not args.daemon:

hindsight-docs/docs/developer/configuration.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ The API service handles all memory operations (retain, recall, reflect).
2424

2525
If not provided, the server uses embedded `pg0` — convenient for development but not recommended for production.
2626

27+
### Database Connection Pool
28+
29+
| Variable | Description | Default |
30+
|----------|-------------|---------|
31+
| `HINDSIGHT_API_DB_POOL_MIN_SIZE` | Minimum connections in the pool | `5` |
32+
| `HINDSIGHT_API_DB_POOL_MAX_SIZE` | Maximum connections in the pool | `100` |
33+
| `HINDSIGHT_API_DB_COMMAND_TIMEOUT` | PostgreSQL command timeout in seconds | `60` |
34+
| `HINDSIGHT_API_DB_ACQUIRE_TIMEOUT` | Connection acquisition timeout in seconds | `30` |
35+
36+
For high-concurrency workloads, increase `DB_POOL_MAX_SIZE`. Each concurrent recall/think operation can use 2-4 connections.
37+
2738
To run migrations manually (e.g., before starting the API), use the admin CLI:
2839

2940
```bash
@@ -266,6 +277,15 @@ Configuration for the local MCP server (`hindsight-local-mcp` command).
266277
export HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take, including tool calls and decisions made."
267278
```
268279

280+
### Background Tasks
281+
282+
Controls background task processing for async operations like opinion formation and entity observations.
283+
284+
| Variable | Description | Default |
285+
|----------|-------------|---------|
286+
| `HINDSIGHT_API_TASK_BATCH_SIZE` | Max tasks to process in one batch | `10` |
287+
| `HINDSIGHT_API_TASK_BATCH_INTERVAL` | Interval between batch processing in seconds | `1.0` |
288+
269289
### Performance Optimization
270290

271291
| Variable | Description | Default |

0 commit comments

Comments
 (0)