@@ -295,6 +295,45 @@ const EnvironmentSchema = z
295295 . int ( )
296296 . default ( 24 * 60 * 60 * 1000 ) , // 1 day in milliseconds
297297
298+ // Master switch for the native realtime backend; off = Electric serves everything, publishes no-op.
299+ REALTIME_BACKEND_NATIVE_ENABLED : z . string ( ) . default ( "0" ) ,
300+ // Live long-poll backstop hold (ms); matches Electric's ~20s cadence.
301+ REALTIME_BACKEND_NATIVE_LIVE_POLL_TIMEOUT_MS : z . coerce . number ( ) . int ( ) . default ( 20_000 ) ,
302+ // Jitter ratio on the live-poll hold (0.15 = ±15%) to avoid synchronized refetch herds.
303+ REALTIME_BACKEND_NATIVE_LIVE_POLL_JITTER_RATIO : z . coerce . number ( ) . default ( 0.15 ) ,
304+ // Hard cap on the tag-list snapshot size.
305+ REALTIME_BACKEND_NATIVE_MAX_LIST_RESULTS : z . coerce . number ( ) . int ( ) . default ( 1_000 ) ,
306+ // TTL/size of the coalescing cache for the multi-run resolve+hydrate (same-filter feeds share one query).
307+ REALTIME_BACKEND_NATIVE_RUNSET_CACHE_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 1_000 ) ,
308+ REALTIME_BACKEND_NATIVE_RUNSET_CACHE_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 5_000 ) ,
309+ // Size/TTL of the per-handle working-set cache used to diff multi-run live polls.
310+ REALTIME_BACKEND_NATIVE_WORKING_SET_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 10_000 ) ,
311+ REALTIME_BACKEND_NATIVE_WORKING_SET_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 300_000 ) ,
312+ // Bucket (ms) the tag-list createdAt floor is quantized to so same-tag feeds share a cache entry; 0 disables.
313+ REALTIME_BACKEND_NATIVE_RUNSET_CREATED_AT_BUCKET_MS : z . coerce . number ( ) . int ( ) . default ( 60_000 ) ,
314+ // Leading-edge throttle (ms) on per-env wake delivery; 0 wakes on every change.
315+ REALTIME_BACKEND_NATIVE_ENV_WAKE_COALESCE_WINDOW_MS : z . coerce . number ( ) . int ( ) . default ( 250 ) ,
316+ // "1" shares per-connection replay cursors fleet-wide via Redis, so a load-balancer hop reads the connection's true inter-poll gap instead of cold-resolving.
317+ REALTIME_BACKEND_NATIVE_SHARED_REPLAY_CURSORS : z . string ( ) . default ( "1" ) ,
318+ // "1" holds a multi-run live poll open on a non-matching wake instead of replying up-to-date.
319+ REALTIME_BACKEND_NATIVE_HOLD_ON_EMPTY : z . string ( ) . default ( "1" ) ,
320+ // Max concurrent fresh ClickHouse resolves per instance (reconnect-stampede gate); 0 disables.
321+ REALTIME_BACKEND_NATIVE_RESOLVE_ADMISSION_LIMIT : z . coerce . number ( ) . int ( ) . default ( 16 ) ,
322+ // Replay window (ms) for buffered change records delivered to newly-armed feeds; 0 disables.
323+ REALTIME_BACKEND_NATIVE_REPLAY_WINDOW_MS : z . coerce . number ( ) . int ( ) . default ( 2_000 ) ,
324+ // Cap on buffered recent records per env (latest record per run).
325+ REALTIME_BACKEND_NATIVE_REPLAY_MAX_RUNS : z . coerce . number ( ) . int ( ) . default ( 512 ) ,
326+ // Keep an env subscribed + buffering this long (ms) after its last feed closes; 0 disables.
327+ REALTIME_BACKEND_NATIVE_UNSUBSCRIBE_LINGER_MS : z . coerce . number ( ) . int ( ) . default ( 5_000 ) ,
328+ // Fallback per-env concurrent-connection limit when the org has none configured.
329+ REALTIME_BACKEND_NATIVE_DEFAULT_CONCURRENCY_LIMIT : z . coerce . number ( ) . int ( ) . default ( 100_000 ) ,
330+ // TTL/size of the single-run read-through cache that collapses duplicate refetch bursts.
331+ REALTIME_BACKEND_NATIVE_RUN_CACHE_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 250 ) ,
332+ REALTIME_BACKEND_NATIVE_RUN_CACHE_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 5_000 ) ,
333+ // TTL/size of the per-org realtimeBackend flag cache used to pick the serving backend.
334+ REALTIME_BACKEND_FLAG_CACHE_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 30_000 ) ,
335+ REALTIME_BACKEND_FLAG_CACHE_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 50_000 ) ,
336+
298337 PUBSUB_REDIS_HOST : z
299338 . string ( )
300339 . optional ( )
@@ -327,6 +366,36 @@ const EnvironmentSchema = z
327366 PUBSUB_REDIS_TLS_DISABLED : z . string ( ) . default ( process . env . REDIS_TLS_DISABLED ?? "false" ) ,
328367 PUBSUB_REDIS_CLUSTER_MODE_ENABLED : z . string ( ) . default ( "0" ) ,
329368
369+ // Dedicated pub/sub Redis for the native realtime backend; falls back to PUBSUB_REDIS_* then REDIS_*.
370+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_HOST : z
371+ . string ( )
372+ . optional ( )
373+ . transform ( ( v ) => v ?? process . env . PUBSUB_REDIS_HOST ?? process . env . REDIS_HOST ) ,
374+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_PORT : z . coerce
375+ . number ( )
376+ . optional ( )
377+ . transform ( ( v ) => {
378+ if ( v !== undefined ) return v ;
379+ const raw = process . env . PUBSUB_REDIS_PORT ?? process . env . REDIS_PORT ;
380+ return raw ? parseInt ( raw ) : undefined ;
381+ } ) ,
382+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_USERNAME : z
383+ . string ( )
384+ . optional ( )
385+ . transform ( ( v ) => v ?? process . env . PUBSUB_REDIS_USERNAME ?? process . env . REDIS_USERNAME ) ,
386+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_PASSWORD : z
387+ . string ( )
388+ . optional ( )
389+ . transform ( ( v ) => v ?? process . env . PUBSUB_REDIS_PASSWORD ?? process . env . REDIS_PASSWORD ) ,
390+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_TLS_DISABLED : z
391+ . string ( )
392+ . default ( process . env . PUBSUB_REDIS_TLS_DISABLED ?? process . env . REDIS_TLS_DISABLED ?? "false" ) ,
393+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_CLUSTER_MODE_ENABLED : z
394+ . string ( )
395+ . default ( process . env . PUBSUB_REDIS_CLUSTER_MODE_ENABLED ?? "0" ) ,
396+ // Use sharded pub/sub (SSUBSCRIBE/SPUBLISH) in cluster mode; "0" forces classic pub/sub.
397+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_SHARDED_ENABLED : z . string ( ) . default ( "1" ) ,
398+
330399 DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT : z . coerce . number ( ) . int ( ) . default ( 100 ) ,
331400 DEFAULT_ENV_EXECUTION_CONCURRENCY_BURST_FACTOR : z . coerce . number ( ) . default ( 1.0 ) ,
332401 DEFAULT_ORG_EXECUTION_CONCURRENCY_LIMIT : z . coerce . number ( ) . int ( ) . default ( 300 ) ,
@@ -1603,6 +1672,18 @@ const EnvironmentSchema = z
16031672 . enum ( [ "log" , "error" , "warn" , "info" , "debug" ] )
16041673 . default ( "info" ) ,
16051674 RUN_ENGINE_CLICKHOUSE_COMPRESSION_REQUEST : z . string ( ) . default ( "1" ) ,
1675+ // Dedicated ClickHouse pool for the native backend's tag/batch id resolution; falls back to CLICKHOUSE_URL.
1676+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_URL : z
1677+ . string ( )
1678+ . optional ( )
1679+ . transform ( ( v ) => v ?? process . env . CLICKHOUSE_URL ) ,
1680+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_KEEP_ALIVE_ENABLED : z . string ( ) . default ( "1" ) ,
1681+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_KEEP_ALIVE_IDLE_SOCKET_TTL_MS : z . coerce . number ( ) . int ( ) . optional ( ) ,
1682+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_MAX_OPEN_CONNECTIONS : z . coerce . number ( ) . int ( ) . default ( 10 ) ,
1683+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_LOG_LEVEL : z
1684+ . enum ( [ "log" , "error" , "warn" , "info" , "debug" ] )
1685+ . default ( "info" ) ,
1686+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_COMPRESSION_REQUEST : z . string ( ) . default ( "1" ) ,
16061687 EVENTS_CLICKHOUSE_BATCH_SIZE : z . coerce . number ( ) . int ( ) . default ( 1000 ) ,
16071688 EVENTS_CLICKHOUSE_FLUSH_INTERVAL_MS : z . coerce . number ( ) . int ( ) . default ( 1000 ) ,
16081689 METRICS_CLICKHOUSE_BATCH_SIZE : z . coerce . number ( ) . int ( ) . default ( 10000 ) ,
0 commit comments