From 39ab748892ecc7aa6eba7e87dfc35cd5e9d74e8b Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Tue, 30 Jun 2026 02:14:06 +0100 Subject: [PATCH] perf(orchestrator): add POSTIZ_ACTIVE_PROVIDERS to limit idle Temporal workers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a default Postiz deployment, getTemporalModule starts one Temporal worker per supported social provider (31 providers + 'main' = 32 workers), regardless of which integrations are actually configured. Each worker long-polls Temporal continuously, causing significant idle CPU/RAM usage even when no posts are scheduled. Root cause (temporal.module.ts): the worker list was built from the full socialIntegrationList with no opt-out mechanism. Fix: introduce an optional POSTIZ_ACTIVE_PROVIDERS env var — a comma- separated list of provider identifiers. When set, only those providers (plus the always-required 'main' worker) start Temporal workers. When unset (the default), all workers start as before — fully backwards-compatible with existing deployments. Example for a deployment using 8 providers: POSTIZ_ACTIVE_PROVIDERS=twitter,instagram,linkedin,bluesky,telegram,facebook,threads,youtube This reduces worker count from 32 to 9, eliminating ~23 idle long-pollers and their associated CPU, RAM, and Postgres connection overhead. Closes #1570 --- .env.example | 2 ++ .../src/temporal/temporal.module.ts | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 1e6f15bff4..3e75b72994 100644 --- a/.env.example +++ b/.env.example @@ -85,6 +85,8 @@ OPENAI_API_KEY="" NEXT_PUBLIC_DISCORD_SUPPORT="" NEXT_PUBLIC_POLOTNO="" # NOT_SECURED=false + +# POSTIZ_ACTIVE_PROVIDERS= API_LIMIT=30 # The limit of the public API hour limit # When connecting providers that take a self-hosted URL (WordPress, Mastodon, diff --git a/libraries/nestjs-libraries/src/temporal/temporal.module.ts b/libraries/nestjs-libraries/src/temporal/temporal.module.ts index 85c54bfd8a..ad3790992b 100644 --- a/libraries/nestjs-libraries/src/temporal/temporal.module.ts +++ b/libraries/nestjs-libraries/src/temporal/temporal.module.ts @@ -1,6 +1,14 @@ import { TemporalModule } from 'nestjs-temporal-core'; import { socialIntegrationList } from '@gitroom/nestjs-libraries/integrations/integration.manager'; +function parseActiveProviders(): Set | null { + const raw = process.env.POSTIZ_ACTIVE_PROVIDERS; + if (!raw || !raw.trim()) return null; + return new Set( + raw.split(',').map((p) => p.trim().toLowerCase()).filter(Boolean) + ); +} + export const getTemporalModule = ( isWorkers: boolean, path?: string, @@ -23,6 +31,10 @@ export const getTemporalModule = ( Number(process.env.WORKER_CONCURRENCY_DIVIDER) || 1 ); + // Providers this server should run workers for (comma-separated). + // Unset => all providers (backwards-compatible default). + const activeProviders = parseActiveProviders(); + return TemporalModule.register({ isGlobal: true, connection: { @@ -46,7 +58,13 @@ export const getTemporalModule = ( integration, taskQueue: integration.identifier.split('-')[0], })) - .filter(({ taskQueue }) => !excludeQueues.includes(taskQueue)) + .filter( + ({ taskQueue }) => + !excludeQueues.includes(taskQueue) && + (taskQueue === 'main' || + activeProviders === null || + activeProviders.has(taskQueue)) + ) .map(({ integration, taskQueue }) => { // Split the per-provider cap across the servers sharing this // queue. Floor (never below 1) so the global total never exceeds