@@ -300,46 +300,36 @@ const EnvironmentSchema = z
300300 . int ( )
301301 . default ( 24 * 60 * 60 * 1000 ) , // 1 day in milliseconds
302302
303- // Master switch for the notifier-backed realtime feed.
304- // "0" (default) = the existing realtime path serves everything, publishes are
305- // no-ops, and no notifier Redis connections are opened (zero-overhead off).
306- // "1" = run-changed signals are published and the per-org `realtimeBackend`
307- // feature flag selects the backend per request.
308- REALTIME_NOTIFIER_ENABLED : z . string ( ) . default ( "0" ) ,
309- // Backstop wait before a live notifier request refetches the run (ms). Matches
310- // Electric's ~20s live long-poll hold so the client polling cadence is unchanged
311- // across backends (a ±15% jitter is applied per request to avoid refetch herds).
312- REALTIME_NOTIFIER_LIVE_POLL_TIMEOUT_MS : z . coerce . number ( ) . int ( ) . default ( 20_000 ) ,
313- // Hard cap on the tag-list snapshot size served by the notifier feed.
314- REALTIME_NOTIFIER_MAX_LIST_RESULTS : z . coerce . number ( ) . int ( ) . default ( 1_000 ) ,
315- // Short-TTL coalescing cache for the multi-run (tag-list/batch) resolve+hydrate.
316- // Concurrent same-filter feeds share one ClickHouse resolve + Postgres hydrate
317- // within this window, so an env-wide wake doesn't fan out into per-feed queries.
318- // Staleness budget: a newly-matching run is visible within ~ttl + poll interval.
319- REALTIME_NOTIFIER_RUNSET_CACHE_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 1_000 ) ,
320- REALTIME_NOTIFIER_RUNSET_CACHE_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 5_000 ) ,
321- // Cap on the per-handle working-set cache (runId -> updatedAt) the notifier keeps
322- // for diffing multi-run live polls.
323- REALTIME_NOTIFIER_WORKING_SET_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 10_000 ) ,
324- // Quantize the tag-list createdAt lower bound to this epoch-aligned bucket (ms) so
325- // same-tag feeds that pin their window within the same bucket share one resolve+
326- // hydrate cache entry. Floored, so the window only ever widens by < bucket. 0
327- // disables bucketing (each feed keeps its exact lower bound).
328- REALTIME_NOTIFIER_RUNSET_CREATED_AT_BUCKET_MS : z . coerce . number ( ) . int ( ) . default ( 60_000 ) ,
329- // Leading-edge throttle (ms) on the per-env wake channel: a busy env's run-change
330- // firehose is collapsed to at most one feed-wake per window, decoupling wake load
331- // from run throughput. Lossless because consumers refetch current state on a wake.
332- // 0 disables coalescing (every change wakes immediately).
333- REALTIME_NOTIFIER_ENV_WAKE_COALESCE_WINDOW_MS : z . coerce . number ( ) . int ( ) . default ( 100 ) ,
334- // When "1", a multi-run live poll woken by a change irrelevant to its filter keeps
335- // holding the long-poll (re-resolving cheaply) instead of returning an empty
336- // up-to-date the client would immediately re-issue. "0" reverts to per-wake replies.
337- REALTIME_NOTIFIER_HOLD_ON_EMPTY : z . string ( ) . default ( "1" ) ,
338- // Max concurrent fresh ClickHouse resolves (cache misses) per instance. Caps the
339- // distinct-filter reconnect stampede: a mass reconnect of N feeds on N different filters
340- // queues to this many concurrent CH queries instead of firing all N at once. Same-filter
341- // bursts collapse via the single-flight cache before taking a permit. 0 disables the gate.
342- REALTIME_NOTIFIER_RESOLVE_ADMISSION_LIMIT : z . coerce . number ( ) . int ( ) . default ( 16 ) ,
303+ // Master switch for the native realtime backend; off = Electric serves everything, publishes no-op.
304+ REALTIME_BACKEND_NATIVE_ENABLED : z . string ( ) . default ( "0" ) ,
305+ // Live long-poll backstop hold (ms); matches Electric's ~20s cadence.
306+ REALTIME_BACKEND_NATIVE_LIVE_POLL_TIMEOUT_MS : z . coerce . number ( ) . int ( ) . default ( 20_000 ) ,
307+ // Jitter ratio on the live-poll hold (0.15 = ±15%) to avoid synchronized refetch herds.
308+ REALTIME_BACKEND_NATIVE_LIVE_POLL_JITTER_RATIO : z . coerce . number ( ) . default ( 0.15 ) ,
309+ // Hard cap on the tag-list snapshot size.
310+ REALTIME_BACKEND_NATIVE_MAX_LIST_RESULTS : z . coerce . number ( ) . int ( ) . default ( 1_000 ) ,
311+ // TTL/size of the coalescing cache for the multi-run resolve+hydrate (same-filter feeds share one query).
312+ REALTIME_BACKEND_NATIVE_RUNSET_CACHE_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 1_000 ) ,
313+ REALTIME_BACKEND_NATIVE_RUNSET_CACHE_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 5_000 ) ,
314+ // Size/TTL of the per-handle working-set cache used to diff multi-run live polls.
315+ REALTIME_BACKEND_NATIVE_WORKING_SET_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 10_000 ) ,
316+ REALTIME_BACKEND_NATIVE_WORKING_SET_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 300_000 ) ,
317+ // Bucket (ms) the tag-list createdAt floor is quantized to so same-tag feeds share a cache entry; 0 disables.
318+ REALTIME_BACKEND_NATIVE_RUNSET_CREATED_AT_BUCKET_MS : z . coerce . number ( ) . int ( ) . default ( 60_000 ) ,
319+ // Leading-edge throttle (ms) on per-env wake delivery; 0 wakes on every change.
320+ REALTIME_BACKEND_NATIVE_ENV_WAKE_COALESCE_WINDOW_MS : z . coerce . number ( ) . int ( ) . default ( 100 ) ,
321+ // "1" holds a multi-run live poll open on a non-matching wake instead of replying up-to-date.
322+ REALTIME_BACKEND_NATIVE_HOLD_ON_EMPTY : z . string ( ) . default ( "1" ) ,
323+ // Max concurrent fresh ClickHouse resolves per instance (reconnect-stampede gate); 0 disables.
324+ REALTIME_BACKEND_NATIVE_RESOLVE_ADMISSION_LIMIT : z . coerce . number ( ) . int ( ) . default ( 16 ) ,
325+ // Fallback per-env concurrent-connection limit when the org has none configured.
326+ REALTIME_BACKEND_NATIVE_DEFAULT_CONCURRENCY_LIMIT : z . coerce . number ( ) . int ( ) . default ( 100_000 ) ,
327+ // TTL/size of the single-run read-through cache that collapses duplicate refetch bursts.
328+ REALTIME_BACKEND_NATIVE_RUN_CACHE_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 250 ) ,
329+ REALTIME_BACKEND_NATIVE_RUN_CACHE_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 5_000 ) ,
330+ // TTL/size of the per-org realtimeBackend flag cache used to pick the serving backend.
331+ REALTIME_BACKEND_FLAG_CACHE_TTL_MS : z . coerce . number ( ) . int ( ) . default ( 30_000 ) ,
332+ REALTIME_BACKEND_FLAG_CACHE_MAX_ENTRIES : z . coerce . number ( ) . int ( ) . default ( 50_000 ) ,
343333
344334 PUBSUB_REDIS_HOST : z
345335 . string ( )
@@ -373,40 +363,35 @@ const EnvironmentSchema = z
373363 PUBSUB_REDIS_TLS_DISABLED : z . string ( ) . default ( process . env . REDIS_TLS_DISABLED ?? "false" ) ,
374364 PUBSUB_REDIS_CLUSTER_MODE_ENABLED : z . string ( ) . default ( "0" ) ,
375365
376- // Dedicated pub/sub Redis for the realtime runs feed's run-changed notifier, so
377- // its publish/subscribe traffic can run on its own instance. Each value falls
378- // back to the shared PUBSUB_REDIS_* (then REDIS_*) when unset, so the default is
379- // unchanged until explicitly pointed at a dedicated instance.
380- REALTIME_RUNS_PUBSUB_REDIS_HOST : z
366+ // Dedicated pub/sub Redis for the native realtime backend; falls back to PUBSUB_REDIS_* then REDIS_*.
367+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_HOST : z
381368 . string ( )
382369 . optional ( )
383370 . transform ( ( v ) => v ?? process . env . PUBSUB_REDIS_HOST ?? process . env . REDIS_HOST ) ,
384- REALTIME_RUNS_PUBSUB_REDIS_PORT : z . coerce
371+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_PORT : z . coerce
385372 . number ( )
386373 . optional ( )
387374 . transform ( ( v ) => {
388375 if ( v !== undefined ) return v ;
389376 const raw = process . env . PUBSUB_REDIS_PORT ?? process . env . REDIS_PORT ;
390377 return raw ? parseInt ( raw ) : undefined ;
391378 } ) ,
392- REALTIME_RUNS_PUBSUB_REDIS_USERNAME : z
379+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_USERNAME : z
393380 . string ( )
394381 . optional ( )
395382 . transform ( ( v ) => v ?? process . env . PUBSUB_REDIS_USERNAME ?? process . env . REDIS_USERNAME ) ,
396- REALTIME_RUNS_PUBSUB_REDIS_PASSWORD : z
383+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_PASSWORD : z
397384 . string ( )
398385 . optional ( )
399386 . transform ( ( v ) => v ?? process . env . PUBSUB_REDIS_PASSWORD ?? process . env . REDIS_PASSWORD ) ,
400- REALTIME_RUNS_PUBSUB_REDIS_TLS_DISABLED : z
387+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_TLS_DISABLED : z
401388 . string ( )
402389 . default ( process . env . PUBSUB_REDIS_TLS_DISABLED ?? process . env . REDIS_TLS_DISABLED ?? "false" ) ,
403- REALTIME_RUNS_PUBSUB_REDIS_CLUSTER_MODE_ENABLED : z
390+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_CLUSTER_MODE_ENABLED : z
404391 . string ( )
405392 . default ( process . env . PUBSUB_REDIS_CLUSTER_MODE_ENABLED ?? "0" ) ,
406- // Use sharded pub/sub (SSUBSCRIBE/SPUBLISH) when in cluster mode, so a busy env's
407- // traffic stays on one shard instead of broadcasting to every node. Only takes
408- // effect alongside CLUSTER_MODE_ENABLED. "0" forces classic pub/sub on the cluster.
409- REALTIME_RUNS_PUBSUB_REDIS_SHARDED_ENABLED : z . string ( ) . default ( "1" ) ,
393+ // Use sharded pub/sub (SSUBSCRIBE/SPUBLISH) in cluster mode; "0" forces classic pub/sub.
394+ REALTIME_BACKEND_NATIVE_PUBSUB_REDIS_SHARDED_ENABLED : z . string ( ) . default ( "1" ) ,
410395
411396 DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT : z . coerce . number ( ) . int ( ) . default ( 100 ) ,
412397 DEFAULT_ENV_EXECUTION_CONCURRENCY_BURST_FACTOR : z . coerce . number ( ) . default ( 1.0 ) ,
@@ -1684,20 +1669,18 @@ const EnvironmentSchema = z
16841669 . enum ( [ "log" , "error" , "warn" , "info" , "debug" ] )
16851670 . default ( "info" ) ,
16861671 RUN_ENGINE_CLICKHOUSE_COMPRESSION_REQUEST : z . string ( ) . default ( "1" ) ,
1687- // ClickHouse client used by the realtime runs feed for tag/batch id resolution.
1688- // Kept on its own URL + pool so the feed's reads can't contend with the main
1689- // analytics client (CLICKHOUSE_URL). Falls back to the main URL when unset.
1690- REALTIME_RUNS_CLICKHOUSE_URL : z
1672+ // Dedicated ClickHouse pool for the native backend's tag/batch id resolution; falls back to CLICKHOUSE_URL.
1673+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_URL : z
16911674 . string ( )
16921675 . optional ( )
16931676 . transform ( ( v ) => v ?? process . env . CLICKHOUSE_URL ) ,
1694- REALTIME_RUNS_CLICKHOUSE_KEEP_ALIVE_ENABLED : z . string ( ) . default ( "1" ) ,
1695- REALTIME_RUNS_CLICKHOUSE_KEEP_ALIVE_IDLE_SOCKET_TTL_MS : z . coerce . number ( ) . int ( ) . optional ( ) ,
1696- REALTIME_RUNS_CLICKHOUSE_MAX_OPEN_CONNECTIONS : z . coerce . number ( ) . int ( ) . default ( 10 ) ,
1697- REALTIME_RUNS_CLICKHOUSE_LOG_LEVEL : z
1677+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_KEEP_ALIVE_ENABLED : z . string ( ) . default ( "1" ) ,
1678+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_KEEP_ALIVE_IDLE_SOCKET_TTL_MS : z . coerce . number ( ) . int ( ) . optional ( ) ,
1679+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_MAX_OPEN_CONNECTIONS : z . coerce . number ( ) . int ( ) . default ( 10 ) ,
1680+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_LOG_LEVEL : z
16981681 . enum ( [ "log" , "error" , "warn" , "info" , "debug" ] )
16991682 . default ( "info" ) ,
1700- REALTIME_RUNS_CLICKHOUSE_COMPRESSION_REQUEST : z . string ( ) . default ( "1" ) ,
1683+ REALTIME_BACKEND_NATIVE_CLICKHOUSE_COMPRESSION_REQUEST : z . string ( ) . default ( "1" ) ,
17011684 EVENTS_CLICKHOUSE_BATCH_SIZE : z . coerce . number ( ) . int ( ) . default ( 1000 ) ,
17021685 EVENTS_CLICKHOUSE_FLUSH_INTERVAL_MS : z . coerce . number ( ) . int ( ) . default ( 1000 ) ,
17031686 METRICS_CLICKHOUSE_BATCH_SIZE : z . coerce . number ( ) . int ( ) . default ( 10000 ) ,
0 commit comments