Skip to content

v0.8.10

Choose a tag to compare

@rmyndharis rmyndharis released this 07 Jul 01:20

Added

  • PostgreSQL schema selection via POSTGRES_SCHEMA. OpenWA's tables and the TypeORM migration ledger can now be placed in a dedicated Postgres schema (default public preserves historical behavior). Set POSTGRES_SCHEMA to isolate OpenWA from other apps sharing a database, or to use a managed-Postgres project schema. The schema must already exist (the built-in container creates it; for external Postgres run CREATE SCHEMA <name>; once). SQLite ignores this setting. The dashboard Infrastructure page exposes the field, and the environment variable is validated as a legal, non-reserved Postgres identifier at boot.

Changed

  • OpenAPI/Swagger tag hygiene. Every controller tag is now declared in the API document (ten were used but undeclared), the three Integration Fabric controllers gained @ApiTags, and the tag casing is uniform — so /api/docs groups every endpoint under a described tag instead of leaving some ungrouped.
  • Graceful shutdown now drains on SIGTERM/SIGINT (rolling deploys, docker stop, Ctrl+C), not just on the admin restart endpoint. On a termination signal the app flips readiness to 503 immediately so a load balancer/orchestrator stops routing, keeps serving in-flight requests for a bounded grace window, then tears down and exits deterministically. ⚠️ Behavior change: a docker stop / redeploy now takes up to the grace window (SHUTDOWN_DELAY_MS, default 3s in production, 0 in dev) plus teardown instead of tearing down instantly, and the process now exits 0 on a clean signal. In Docker set stop_grace_periodSHUTDOWN_DELAY_MS + your worst-case teardown (the bundled compose now sets 45s); for Kubernetes set terminationGracePeriodSeconds accordingly. A second signal during the drain forces an immediate exit. The whatsapp-web.js engine no longer lets Puppeteer install its own signal handlers (which previously killed Chromium at signal time / exit(130) before the drain could run).
  • The bundled Docker Compose stack pins its docker-socket-proxy and minio images to explicit tags (they were on :latest) for reproducible, non-drifting deploys, and a Dependabot docker ecosystem was added so base and stack images keep receiving update PRs. A Node >=22 engines floor + .nvmrc were declared, and the transitive install-time Scarf telemetry (via swagger-ui-dist) is disabled.

Fixed

  • The Integration Fabric now works on PostgreSQL. conversation_mappings and integration_delivery_failures declared @PrimaryGeneratedColumn('uuid') ids but their columns were created without a Postgres DEFAULT gen_random_uuid(), so on PostgreSQL every first insert failed with a NOT NULL violation on id — breaking the plugin conversation-mapping upsert (e.g. the Chatwoot handover) and the ingress dead-letter write. SQLite was unaffected because its driver mints the uuid client-side, which is why it went unnoticed. A forward-only migration adds the default (no-op on SQLite). A new CI job now applies the full migration chain against a real PostgreSQL and asserts every generated-uuid primary key has a database default, so this dialect gap can't recur.
  • Indexed webhooks.sessionId. The webhook dispatch path looks up a session's active webhooks by sessionId on every emitted event, so on a busy session this was a full table scan of the webhooks table per event (the foreign-key column carried no index). A cross-dialect index migration — plus the matching entity index — makes the lookup index-backed.
  • Boot now rejects a non-canonical boolean feature flag instead of silently disabling the feature. QUEUE_ENABLED, MCP_ENABLED, and SERVE_DASHBOARD are read with an exact === 'true' / !== 'false' comparison, so a typo (True, 1, yes) or a stray trailing space/CR (a Windows-edited env file forwarded verbatim by docker run --env-file) silently (dis)abled the feature with zero diagnostics. These are now validated at startup and boot fails fast naming the offending key. ⚠️ Behavior change: a deployment currently booting with such a value (e.g. QUEUE_ENABLED=1) will now refuse to start until corrected to true/false/unset — including SERVE_DASHBOARD=0/no, which was silently serving the dashboard and will now correctly disable it once set to false.
  • A fatal uncaught exception is now written to the structured log (with its stack and origin) before the process exits, instead of only a raw stack on stderr that the log pipeline missed. This is observe-only: the crash-and-restart posture is unchanged (the container restart policy still fires and the process never continues on corrupted post-exception state).
  • POST /infra/import-data no longer swallows a genuine database error while clearing tables. The table-clearing step tolerated only a genuinely-absent table but previously used a blanket catch, so an I/O/lock error (or an aborted transaction) could let a restore commit a merged rather than replaced dataset on SQLite. Such errors now surface and roll the whole import back (a real fault returns a 500 carrying the actual cause); the intended tolerance for a missing table is preserved.
  • A session no longer schedules a reconnect while the process is shutting down — a disconnect during the drain window would otherwise launch a fresh Chromium racing the shutdown teardown. The session is left DISCONNECTED (a later start / auto-restore re-initializes it cleanly).
  • Documentation & config accuracy. .env.example now documents PORT (the port the app binds to on bare metal) distinctly from the Compose-only host-published API_PORT, and adds the QUEUE_ENABLED/CACHE_ENABLED toggles. SECURITY.md's supported-versions table and the Java SDK install snippets are refreshed to the current releases. The unused uuid/@types/uuid dependency was removed, and stale "not yet wired" comments on the plugin ingress-manifest validation (which the loader has called since it shipped) were corrected.
  • The bundled Docker Compose stack no longer kills Chromium mid-spawn under multi-session whatsapp-web.js workloads (#636). The per-container pids_limit shipped at 512 since the #243 hardening pass — a fork-bomb guard chosen without accounting for Chromium's multi-process model. whatsapp-web.js runs a full Chromium instance per session (browser + renderer + GPU + zygote + utilities), and WhatsApp Web is itself process-heavy, so ~4 concurrent sessions already approached 512 and the next session's Chromium was killed mid-spawn when fork() returned EAGAIN — surfacing in the API as a Failed to launch the browser process: Code: null launch failure with no useful log (the dbus/crashpad noise in the log is non-fatal). The default is now 2048 (fits ~8–10 sessions with startup-spike headroom), exposed as OPENWA_PIDS_LIMIT for larger fleets. The limit is a cgroup pids.max ceiling, not an allocation — raising it is a no-op for light containers, so this is safe for the baileys engine (single-process, no Chromium, a handful of PIDs regardless). The fork-bomb guard stays finite (-1/unlimited is explicitly discouraged). A new troubleshooting entry distinguishes the three causes of Code: null (PID exhaustion vs OOM-kill vs the XDG/crashpad crash already fixed earlier), since the cause isn't visible in the log without docker stats / dmesg.