From 29598a77b834933ca485634bce6b25b0e45addb8 Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Mon, 13 Jul 2026 17:17:02 +0100 Subject: [PATCH] feat(webapp): add option to disable PostgreSQL task-event writes (#4242) ## Summary Adds `EVENT_REPOSITORY_POSTGRES_WRITES_DISABLED` (default off), which makes the task-event store skip all PostgreSQL `TaskEvent` writes. It's for deployments that store task events in ClickHouse (`EVENT_REPOSITORY_DEFAULT_STORE=clickhouse_v2`) and no longer want the PostgreSQL copy. ## How it works The guard sits at the single postgres write boundary, `TaskEventStore.create` / `createMany`, so it covers every write path (OTLP ingestion and run-lifecycle events) with one check. Reads are untouched (`findMany` / trace queries / streaming), so existing PostgreSQL events remain readable. Leave it off unless the default store is `clickhouse_v2`, otherwise task events for any run still routed to PostgreSQL would be dropped. --- .../disable-postgres-task-event-writes.md | 6 ++++++ apps/webapp/app/env.server.ts | 1 + .../v3/eventRepository/eventRepository.server.ts | 13 +++++++++++-- docs/self-hosting/env/webapp.mdx | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 .server-changes/disable-postgres-task-event-writes.md diff --git a/.server-changes/disable-postgres-task-event-writes.md b/.server-changes/disable-postgres-task-event-writes.md new file mode 100644 index 000000000..47eb9ef9f --- /dev/null +++ b/.server-changes/disable-postgres-task-event-writes.md @@ -0,0 +1,6 @@ +--- +area: webapp +type: feature +--- + +Added `EVENT_REPOSITORY_POSTGRES_WRITES_DISABLED` to skip all PostgreSQL task-event writes for deployments that store task events in ClickHouse. Leave it off unless `EVENT_REPOSITORY_DEFAULT_STORE` is `clickhouse_v2`, otherwise task events are lost. diff --git a/apps/webapp/app/env.server.ts b/apps/webapp/app/env.server.ts index da67a3dcc..9554120a6 100644 --- a/apps/webapp/app/env.server.ts +++ b/apps/webapp/app/env.server.ts @@ -1860,6 +1860,7 @@ const EnvironmentSchema = z .enum(["postgres", "clickhouse", "clickhouse_v2"]) .default("postgres"), EVENT_REPOSITORY_DEBUG_LOGS_DISABLED: BoolEnv.default(false), + EVENT_REPOSITORY_POSTGRES_WRITES_DISABLED: BoolEnv.default(false), EVENTS_CLICKHOUSE_MAX_TRACE_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(25_000), EVENTS_CLICKHOUSE_MAX_TRACE_DETAILED_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(5_000), EVENTS_CLICKHOUSE_MAX_LIVE_RELOADING_SETTING: z.coerce.number().int().default(2000), diff --git a/apps/webapp/app/v3/eventRepository/eventRepository.server.ts b/apps/webapp/app/v3/eventRepository/eventRepository.server.ts index 2de5ce8b2..ea778fb53 100644 --- a/apps/webapp/app/v3/eventRepository/eventRepository.server.ts +++ b/apps/webapp/app/v3/eventRepository/eventRepository.server.ts @@ -157,14 +157,23 @@ export class EventRepository implements IEventRepository { } private async insertImmediate(event: CreateEventInput) { + if (env.EVENT_REPOSITORY_POSTGRES_WRITES_DISABLED) { + return; + } await this.#flushBatch(nanoid(), [this.#createableEventToPrismaEvent(event)]); } insertMany(events: CreateEventInput[]) { + if (env.EVENT_REPOSITORY_POSTGRES_WRITES_DISABLED) { + return; + } this._flushScheduler.addToBatch(events.map(this.#createableEventToPrismaEvent)); } async insertManyImmediate(events: CreateEventInput[]) { + if (env.EVENT_REPOSITORY_POSTGRES_WRITES_DISABLED) { + return; + } await this.#flushBatchWithReturn(nanoid(), events.map(this.#createableEventToPrismaEvent)); } @@ -1018,7 +1027,7 @@ export class EventRepository implements IEventRepository { if (options.immediate) { await this.insertImmediate(event); } else { - this._flushScheduler.addToBatch([this.#createableEventToPrismaEvent(event)]); + this.insertMany([event]); } } @@ -1152,7 +1161,7 @@ export class EventRepository implements IEventRepository { if (options.immediate) { await this.insertImmediate(event); } else { - this._flushScheduler.addToBatch([this.#createableEventToPrismaEvent(event)]); + this.insertMany([event]); } return result; diff --git a/docs/self-hosting/env/webapp.mdx b/docs/self-hosting/env/webapp.mdx index d4e8b16ff..1f629718b 100644 --- a/docs/self-hosting/env/webapp.mdx +++ b/docs/self-hosting/env/webapp.mdx @@ -135,6 +135,7 @@ mode: "wide" | `SERVER_OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` | No | 8192 | OTel span attribute value length limit. | | **Task events** | | | | | `EVENT_REPOSITORY_DEFAULT_STORE` | No | postgres | Where to store task events. Set to `clickhouse_v2` to store in ClickHouse (recommended for production). | +| `EVENT_REPOSITORY_POSTGRES_WRITES_DISABLED` | No | 0 | Skip all PostgreSQL task-event writes (set to `1`). Only enable when `EVENT_REPOSITORY_DEFAULT_STORE` is `clickhouse_v2`, otherwise task events are lost. | | **Realtime** | | | | | `REALTIME_STREAM_VERSION` | No | v1 | Stream version exposed to tasks via the `TRIGGER_REALTIME_STREAM_VERSION` variable. Distinct from `REALTIME_STREAMS_DEFAULT_VERSION`. One of `v1`, `v2`. | | `REALTIME_STREAM_MAX_LENGTH` | No | 1000 | Realtime stream max length. |