Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .server-changes/realtime-backend-default-env.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: improvement
---

Add a `REALTIME_BACKEND_DEFAULT` env var to choose the default realtime backend (`electric`, `native`, or `shadow`) for environments whose org has no per-org override. Defaults to `electric`, so existing behavior is unchanged.
2 changes: 2 additions & 0 deletions apps/webapp/app/env.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ const EnvironmentSchema = z

// Master switch for the native realtime backend; off = Electric serves everything, publishes no-op.
REALTIME_BACKEND_NATIVE_ENABLED: z.string().default("0"),
// Default backend when an org has no `realtimeBackend` override and no global flag row is set.
REALTIME_BACKEND_DEFAULT: z.enum(["electric", "native", "shadow"]).default("electric"),
// Live long-poll backstop hold (ms); matches Electric's ~20s cadence.
REALTIME_BACKEND_NATIVE_LIVE_POLL_TIMEOUT_MS: z.coerce.number().int().default(20_000),
// Jitter ratio on the live-poll hold (0.15 = ±15%) to avoid synchronized refetch herds.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { getShadowRealtimeClient } from "./shadowRealtimeClientInstance.server";

type RealtimeBackend = "electric" | "native" | "shadow";

// Two gates, both defaulting to the Electric path: the env master switch, then the
// per-org `realtimeBackend` feature flag (cached so long-polls don't hit the DB per request).
// Two gates: the env master switch, then the per-org `realtimeBackend` feature flag (cached so
// long-polls don't hit the DB per request), falling back to REALTIME_BACKEND_DEFAULT.
const nativeBackendEnabled = env.REALTIME_BACKEND_NATIVE_ENABLED === "1";

const flag = singleton("realtimeBackendFlag", () => makeFlag($replica));
Expand Down Expand Up @@ -61,7 +61,7 @@ async function getRealtimeBackend(
return cached;
}

let backend: RealtimeBackend = "electric";
let backend: RealtimeBackend = env.REALTIME_BACKEND_DEFAULT;

try {
const overrides =
Expand All @@ -76,7 +76,7 @@ async function getRealtimeBackend(

backend = await flag({
key: FEATURE_FLAG.realtimeBackend,
defaultValue: "electric",
defaultValue: env.REALTIME_BACKEND_DEFAULT,
overrides: (overrides as Record<string, unknown>) ?? {},
});
} catch (error) {
Expand All @@ -85,7 +85,7 @@ async function getRealtimeBackend(
organizationId,
error,
});
backend = "electric";
backend = env.REALTIME_BACKEND_DEFAULT;
}

backendCache.set(organizationId, backend);
Expand Down