Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ impl ServeConfig {
serverless_validate_endpoint: settings.serverless_validate_endpoint,
serverless_max_start_payload_bytes: settings.serverless_max_start_payload_bytes,
serverless_cache_envoy: true,
force_normal_runner_config_upsert: false,
}
}
}
Expand Down
6 changes: 1 addition & 5 deletions rivetkit-rust/packages/rivetkit-core/src/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,6 @@ pub struct ServeConfig {
pub serverless_validate_endpoint: bool,
pub serverless_max_start_payload_bytes: usize,
pub serverless_cache_envoy: bool,
/// When true, upsert a normal runner config to the engine on startup
/// even if the endpoint is not a local engine. Set by the TS Registry
/// when `RIVETKIT_RUNTIME_MODE` resolves to `envoy`.
pub force_normal_runner_config_upsert: bool,
}

#[derive(Debug, Default, Deserialize)]
Expand Down Expand Up @@ -505,7 +501,7 @@ impl CoreRegistry {
}

#[cfg(feature = "native-runtime")]
runner_config::ensure_normal_runner_config(&config).await?;
runner_config::ensure_local_normal_runner_config(&config).await?;
let callbacks = Arc::new(RegistryCallbacks {
dispatcher: dispatcher.clone(),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ struct Datacenter {
name: String,
}

pub(super) async fn ensure_normal_runner_config(config: &ServeConfig) -> Result<()> {
if !is_local_engine_endpoint(&config.endpoint) && !config.force_normal_runner_config_upsert {
pub(super) async fn ensure_local_normal_runner_config(config: &ServeConfig) -> Result<()> {
if !is_local_engine_endpoint(&config.endpoint) {
return Ok(());
}

Expand Down Expand Up @@ -51,15 +51,15 @@ pub(super) async fn ensure_normal_runner_config(config: &ServeConfig) -> Result<
.json(&body)
.send()
.await
.context("upsert normal runner config")?;
.context("upsert local runner config")?;
let status = response.status();
if !status.is_success() {
let response_body = response
.text()
.await
.context("read failed runner config response body")?;
anyhow::bail!(
"failed to upsert normal runner config `{}`: {} {}",
"failed to upsert local runner config `{}`: {} {}",
config.pool_name,
status,
response_body
Expand All @@ -69,7 +69,7 @@ pub(super) async fn ensure_normal_runner_config(config: &ServeConfig) -> Result<
tracing::debug!(
namespace = %config.namespace,
pool_name = %config.pool_name,
"ensured normal runner config"
"ensured local normal runner config"
);

Ok(())
Expand All @@ -80,15 +80,15 @@ async fn get_datacenters(client: &Client, config: &ServeConfig) -> Result<Datace
let response = apply_auth(client.get(url), config)
.send()
.await
.context("get datacenters")?;
.context("get local datacenters")?;
let status = response.status();
if !status.is_success() {
let response_body = response
.text()
.await
.context("read failed datacenters response body")?;
anyhow::bail!(
"failed to get datacenters for runner config: {} {}",
"failed to get local datacenters for runner config: {} {}",
status,
response_body
);
Expand Down
1 change: 0 additions & 1 deletion rivetkit-rust/packages/rivetkit-core/tests/serverless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ mod moved_tests {
serverless_validate_endpoint: true,
serverless_max_start_payload_bytes: 1_048_576,
serverless_cache_envoy: true,
force_normal_runner_config_upsert: false,
}
}

Expand Down
1 change: 0 additions & 1 deletion rivetkit-typescript/packages/rivetkit-napi/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ export interface JsServeConfig {
serverlessClientToken?: string
serverlessValidateEndpoint: boolean
serverlessMaxStartPayloadBytes: number
forceNormalRunnerConfigUpsert?: boolean
}
export interface JsListenerConfig {
/** Host to bind. Defaults to `0.0.0.0` when not provided. */
Expand Down
4 changes: 0 additions & 4 deletions rivetkit-typescript/packages/rivetkit-napi/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ pub struct JsServeConfig {
pub serverless_client_token: Option<String>,
pub serverless_validate_endpoint: bool,
pub serverless_max_start_payload_bytes: u32,
pub force_normal_runner_config_upsert: Option<bool>,
}

#[napi(object)]
Expand Down Expand Up @@ -657,9 +656,6 @@ fn serve_config_from_js(
serverless_validate_endpoint: config.serverless_validate_endpoint,
serverless_max_start_payload_bytes: config.serverless_max_start_payload_bytes as usize,
serverless_cache_envoy,
force_normal_runner_config_upsert: config
.force_normal_runner_config_upsert
.unwrap_or(false),
}
}

Expand Down
5 changes: 0 additions & 5 deletions rivetkit-typescript/packages/rivetkit/src/registry/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { SqliteNativeMetrics } from "@/common/database/config";
import { getRivetkitRuntimeMode } from "@/utils/env-vars";
import type { RegistryConfig } from "./config";

declare const handleBrand: unique symbol;
Expand Down Expand Up @@ -244,7 +243,6 @@ export interface RuntimeServeConfig {
serverlessClientToken?: string;
serverlessValidateEndpoint: boolean;
serverlessMaxStartPayloadBytes: number;
forceNormalRunnerConfigUpsert?: boolean;
}

export interface RuntimeListenerConfig {
Expand Down Expand Up @@ -601,9 +599,6 @@ export async function buildServeConfig(
serveConfig.inspectorTestToken =
process.env._RIVET_TEST_INSPECTOR_TOKEN ?? "token";
}
if (getRivetkitRuntimeMode() === "envoy") {
serveConfig.forceNormalRunnerConfigUpsert = true;
}

return serveConfig;
}
12 changes: 4 additions & 8 deletions rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,10 @@ export const getRivetkitRuntime = (): string | undefined =>
getEnvUniversal("RIVETKIT_RUNTIME");
export type RuntimeMode = "envoy" | "serverless";

export const getRivetkitRuntimeMode = (): RuntimeMode => {
const explicit = getEnvUniversal("RIVETKIT_RUNTIME_MODE");
if (explicit === "envoy" || explicit === "serverless") return explicit;
const railwayId = getEnvUniversal("RAILWAY_DEPLOYMENT_ID");
if (railwayId !== undefined && railwayId !== "") return "envoy";
if (getNodeEnv() === "production") return "serverless";
return "envoy";
};
export const getRivetkitRuntimeMode = (): RuntimeMode =>
getEnvUniversal("RIVETKIT_RUNTIME_MODE") === "serverless"
? "serverless"
: "envoy";

export const getRivetkitPublicDir = (): string | undefined => {
const value = getEnvUniversal("RIVETKIT_PUBLIC_DIR");
Expand Down
57 changes: 12 additions & 45 deletions rivetkit-typescript/packages/rivetkit/tests/listener.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,73 +5,40 @@ import type { Registry } from "@/registry";
import { getRivetkitRuntimeMode, parsePortEnv } from "@/utils/env-vars";

describe("getRivetkitRuntimeMode", () => {
const KEYS = [
"RIVETKIT_RUNTIME_MODE",
"RAILWAY_DEPLOYMENT_ID",
"NODE_ENV",
] as const;
let snapshot: Record<string, string | undefined>;
let snapshot: string | undefined;

beforeEach(() => {
snapshot = Object.fromEntries(KEYS.map((k) => [k, process.env[k]]));
for (const k of KEYS) delete process.env[k];
snapshot = process.env.RIVETKIT_RUNTIME_MODE;
delete process.env.RIVETKIT_RUNTIME_MODE;
});
afterEach(() => {
for (const k of KEYS) {
if (snapshot[k] === undefined) delete process.env[k];
else process.env[k] = snapshot[k];
}
if (snapshot === undefined) delete process.env.RIVETKIT_RUNTIME_MODE;
else process.env.RIVETKIT_RUNTIME_MODE = snapshot;
});

test("dev default (no env) is envoy", () => {
test("default (unset) is envoy", () => {
expect(getRivetkitRuntimeMode()).toBe("envoy");
});

test("NODE_ENV=production defaults to serverless", () => {
process.env.NODE_ENV = "production";
test("explicit serverless", () => {
process.env.RIVETKIT_RUNTIME_MODE = "serverless";
expect(getRivetkitRuntimeMode()).toBe("serverless");
});

test("RAILWAY_DEPLOYMENT_ID set defaults to envoy", () => {
process.env.RAILWAY_DEPLOYMENT_ID = "dep_123";
expect(getRivetkitRuntimeMode()).toBe("envoy");
});

test("Railway overrides NODE_ENV=production", () => {
process.env.RAILWAY_DEPLOYMENT_ID = "dep_123";
process.env.NODE_ENV = "production";
expect(getRivetkitRuntimeMode()).toBe("envoy");
});

test("explicit envoy wins over NODE_ENV=production", () => {
test("explicit envoy", () => {
process.env.RIVETKIT_RUNTIME_MODE = "envoy";
process.env.NODE_ENV = "production";
expect(getRivetkitRuntimeMode()).toBe("envoy");
});

test("explicit serverless wins over Railway", () => {
process.env.RIVETKIT_RUNTIME_MODE = "serverless";
process.env.RAILWAY_DEPLOYMENT_ID = "dep_123";
expect(getRivetkitRuntimeMode()).toBe("serverless");
});

test("empty string falls through to next rule", () => {
test("empty string is envoy", () => {
process.env.RIVETKIT_RUNTIME_MODE = "";
process.env.NODE_ENV = "production";
expect(getRivetkitRuntimeMode()).toBe("serverless");
expect(getRivetkitRuntimeMode()).toBe("envoy");
});

test("unrecognized value falls through to next rule", () => {
test("unrecognized value is envoy", () => {
process.env.RIVETKIT_RUNTIME_MODE = "potato";
process.env.RAILWAY_DEPLOYMENT_ID = "dep_123";
expect(getRivetkitRuntimeMode()).toBe("envoy");
});

test("RAILWAY_DEPLOYMENT_ID empty is treated as unset; falls through to NODE_ENV", () => {
process.env.RAILWAY_DEPLOYMENT_ID = "";
process.env.NODE_ENV = "production";
expect(getRivetkitRuntimeMode()).toBe("serverless");
});
});

describe("parsePortEnv", () => {
Expand Down
3 changes: 1 addition & 2 deletions website/src/content/docs/general/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ These variables configure how clients connect to your actors.

| Environment Variable | Description |
|---------------------|-------------|
| `RIVETKIT_RUNTIME_MODE` | Controls how `registry.start()` runs. `envoy` opens a long-lived WebSocket to the engine (Mode A) and auto-upserts a normal runner config to the engine on startup (even against remote endpoints). `serverless` binds an HTTP listener via `registry.listen()` (Mode B) and leaves runner-config management to the caller. Resolution: explicit value > `RAILWAY_DEPLOYMENT_ID` set → `envoy` > `NODE_ENV=production` → `serverless` > dev default `envoy`. |
| `RAILWAY_DEPLOYMENT_ID` | Automatically set by Railway. RivetKit uses presence to default `RIVETKIT_RUNTIME_MODE=envoy` when not explicitly set. |
| `RIVETKIT_RUNTIME_MODE` | Controls how `registry.start()` runs. Defaults to `envoy`: opens a long-lived WebSocket to the engine (Mode A). Set to `serverless` to bind an HTTP listener via `registry.listen()` (Mode B). |
| `RIVETKIT_PUBLIC_DIR` | Directory of static assets to serve alongside the framework routes when calling `registry.listen()`. Used as a fallback when `opts.publicDir` is not passed. On auto-listen via `registry.start()`, defaults to `/public` when this env var is unset. |

## Logging
Expand Down
Loading