All three were missing the transient-connection retry that sql_update and
run_sql_select already had. On OperationalError (stale/dropped connection),
each now retries once with a fresh engine.connect() without disposing the pool.
IntegrityError (duplicate key, FK violation, NOT NULL) continues to return
None without retrying — the same data would fail again and None signals a
data conflict to callers, distinct from False (error) or an int (success).
sql_insert_or_update retry is safe because ON DUPLICATE KEY UPDATE is idempotent.
sql_insert retry is safe because OperationalError means MariaDB rolled back.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wraps the deprecated global `db = engine.connect()` in a try/except so
a Docker startup race (MariaDB not yet ready) no longer crashes the
Gunicorn worker before it can serve any requests.
Sets db=None on failure; reconnect_db() on the lifespan bootstrap path
re-establishes it once credentials are confirmed.
TODO (P3 full): migrate lib_schema_v3.py:39 and lib_api_crud_v3.py:166
off the global db to engine.connect() context managers, then remove it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added AE_DB_POOL_SIZE and AE_DB_POOL_MAX_OVERFLOW to config.py with
defaults matching prior hardcoded values (10/20). Wired into settings.DB
property so create_ae_engine() reads them without fallback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On OperationalError, sql_update and run_sql_select were calling
sql_connect() → reconnect_db() which disposes the entire connection
pool mid-flight, killing other in-flight connections under concurrency.
Removed the sql_connect() calls; the existing retry blocks already open
a fresh engine.connect() context manager, and pool_pre_ping=True handles
stale connection detection. Also drops the now-unused sql_connect import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#3 (zombie import) is genuinely a 2-line fix — remove the import from api.py:10 and move db_connection.py to trash. Zero functional change since db is only in a commented-out line.
- Add confirmed Novi API patterns (auth, field names, endpoints)
- List remaining unknowns and data_store credential setup requirements
- Add pydantic/SQLAlchemy migration notes
- Summarize completed operational hardening and BuildKit cache work
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app/methods/e_novi_mailman_methods.py: full sync engine, per-member
sync helper, webhook handler, and Mailman 3 REST subscribe/unsubscribe
- app/routers/api_v3_actions_e_novi_mailman.py: test_connection, list
inspection, full sync trigger, and Novi webhook receiver endpoints
- registry.py: registered at /v3/action/e_novi_mailman
- TODO: marked as scaffolded, pending Novi field verification + data_store setup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: enable BuildKit syntax, use --mount=type=cache for pip to speed up rebuilds
- requirements.txt: relax fastapi==0.115.5 → fastapi>=0.115.5
- TODO: mark Locking task as complete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>