Skip to content

Commit 1919c35

Browse files
committed
chore: fix driver test suite
1 parent d52f9f7 commit 1919c35

97 files changed

Lines changed: 2635 additions & 770 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,10 @@ let error_with_meta = ApiRateLimited { limit: 100, reset_at: 1234567890 }.build(
284284
- Connection pooling through `packages/common/pools/`
285285

286286
**Performance**
287-
- ALWAYS prefer a dedicated concurrency container like `scc::HashMap<_, _>` with its async api or `moka::Cache` over `Arc<Mutex<HashMap<_, _>>>`. `Arc<Mutex<_>>` is very slow for containers.
287+
- Never use `Mutex<HashMap<...>>` or `RwLock<HashMap<...>>`.
288+
- Use `scc::HashMap` (preferred), `moka::Cache` (for TTL/bounded), or `DashMap` for concurrent maps.
289+
- Use `scc::HashSet` instead of `Mutex<HashSet<...>>` for concurrent sets.
290+
- `scc` async methods do not hold locks across `.await` points. Use `entry_async` for atomic read-then-write.
288291

289292
### Code Style
290293
- Hard tabs for Rust formatting (see `rustfmt.toml`)

Cargo.lock

Lines changed: 13 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ members = [
4646
"engine/packages/universaldb",
4747
"engine/packages/universalpubsub",
4848
"engine/packages/util",
49+
"engine/packages/util-serde",
4950
"engine/packages/util-id",
5051
"engine/packages/workflow-worker",
5152
"engine/sdks/rust/api-full",
@@ -488,6 +489,9 @@ members = [
488489
package = "rivet-util"
489490
path = "engine/packages/util"
490491

492+
[workspace.dependencies.rivet-util-serde]
493+
path = "engine/packages/util-serde"
494+
491495
[workspace.dependencies.rivet-util-id]
492496
path = "engine/packages/util-id"
493497

engine/CLAUDE.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ When changing a versioned VBARE schema, follow the existing migration pattern.
3333
- When adding fields to epoxy workflow state structs, mark them `#[serde(default)]` so Gasoline can replay older serialized state.
3434
- Epoxy integration tests that spin up `tests/common::TestCtx` must call `shutdown()` before returning.
3535

36-
## Concurrent containers
37-
38-
Never use `Mutex<HashMap<...>>` or `RwLock<HashMap<...>>`. Use `scc::HashMap` (preferred), `moka::Cache` (for TTL/bounded), or `DashMap`. Same for sets: use `scc::HashSet` instead of `Mutex<HashSet<...>>`. Note that `scc` async methods do not hold locks across `.await` points. Use `entry_async` for atomic read-then-write.
39-
4036
## Test snapshots
4137

4238
Use `test-snapshot-gen` to generate and load RocksDB snapshots of the full UDB KV store for migration and integration tests. Scenarios produce per-replica RocksDB checkpoints stored under `engine/packages/test-snapshot-gen/snapshots/` (git LFS tracked). In tests, use `test_snapshot::SnapshotTestCtx::from_snapshot("scenario-name")` to boot a cluster from snapshot data. See `docs-internal/engine/TEST_SNAPSHOTS.md` for the full guide.

engine/packages/guard/src/routing/pegboard_gateway/resolve_actor_query.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,27 @@ async fn resolve_query_target_dc_label(
207207
}
208208

209209
fn serialize_actor_key(key: &[String]) -> Result<String> {
210-
serde_json::to_string(key).context("failed to serialize actor key")
210+
const EMPTY_KEY: &str = "/";
211+
const KEY_SEPARATOR: char = '/';
212+
213+
if key.is_empty() {
214+
return Ok(EMPTY_KEY.to_string());
215+
}
216+
217+
let mut escaped_parts = Vec::with_capacity(key.len());
218+
for part in key {
219+
if part.is_empty() {
220+
escaped_parts.push(String::from("\\0"));
221+
continue;
222+
}
223+
224+
let escaped = part
225+
.replace('\\', "\\\\")
226+
.replace(KEY_SEPARATOR, "\\/");
227+
escaped_parts.push(escaped);
228+
}
229+
230+
Ok(escaped_parts.join(EMPTY_KEY))
211231
}
212232

213233
fn is_duplicate_key_error(err: &anyhow::Error) -> bool {

engine/packages/pegboard/src/ops/actor/create.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ pub async fn pegboard_actor_create(ctx: &OperationCtx, input: &Input) -> Result<
4747
ctx.subscribe::<crate::workflows::actor2::DestroyStarted>(("actor_id", input.actor_id)),
4848
ctx.op(crate::ops::runner_config::get::Input {
4949
runners: vec![(input.namespace_id, input.runner_name_selector.clone())],
50-
bypass_cache: false,
50+
// Actor creation needs the latest protocol version immediately after
51+
// serverless metadata refresh so fresh pools can start on actor2
52+
// without waiting for the runner-config cache to expire.
53+
bypass_cache: true,
5154
}),
5255
)?;
5356

engine/sdks/rust/envoy-client/src/connection.rs

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

engine/sdks/rust/envoy-client/src/envoy.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

engine/sdks/rust/envoy-client/src/handle.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rivetkit-typescript/packages/rivetkit-native/index.d.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33

44
/* auto-generated by NAPI-RS */
55

6+
export interface JsBindParam {
7+
kind: string
8+
intValue?: number
9+
floatValue?: number
10+
textValue?: string
11+
blobValue?: Buffer
12+
}
13+
export interface ExecuteResult {
14+
changes: number
15+
}
16+
export interface QueryResult {
17+
columns: Array<string>
18+
rows: Array<Array<any>>
19+
}
620
/** Open a native SQLite database backed by the envoy's KV channel. */
721
export declare function openDatabaseFromEnvoy(jsHandle: JsEnvoyHandle, actorId: string): Promise<JsNativeDatabase>
822
/** Configuration for starting the native envoy client. */
@@ -44,7 +58,12 @@ export declare function startEnvoySyncJs(config: JsEnvoyConfig, eventCallback: (
4458
/** Start the native envoy client asynchronously. */
4559
export declare function startEnvoyJs(config: JsEnvoyConfig, eventCallback: (event: any) => void): JsEnvoyHandle
4660
/** Native SQLite database handle exposed to JavaScript. */
47-
export declare class JsNativeDatabase { }
61+
export declare class JsNativeDatabase {
62+
run(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<ExecuteResult>
63+
query(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<QueryResult>
64+
exec(sql: string): Promise<QueryResult>
65+
close(): Promise<void>
66+
}
4867
/** Native envoy handle exposed to JavaScript via N-API. */
4968
export declare class JsEnvoyHandle {
5069
started(): Promise<void>
@@ -64,10 +83,10 @@ export declare class JsEnvoyHandle {
6483
kvDrop(actorId: string): Promise<void>
6584
restoreHibernatingRequests(actorId: string, requests: Array<HibernatingRequestEntry>): void
6685
sendHibernatableWebSocketMessageAck(gatewayId: Buffer, requestId: Buffer, clientMessageIndex: number): void
67-
startServerless(payload: Buffer): Promise<void>
68-
/** Send a message on an open WebSocket connection. */
69-
sendWsMessage(gatewayId: Buffer, requestId: Buffer, data: Buffer, binary: boolean): void
86+
/** Send a message on an open WebSocket connection identified by messageIdHex. */
87+
sendWsMessage(gatewayId: Buffer, requestId: Buffer, data: Buffer, binary: boolean): Promise<void>
7088
/** Close an open WebSocket connection. */
71-
closeWebsocket(gatewayId: Buffer, requestId: Buffer, code?: number | undefined | null, reason?: string | undefined | null): void
89+
closeWebsocket(gatewayId: Buffer, requestId: Buffer, code?: number | undefined | null, reason?: string | undefined | null): Promise<void>
90+
startServerless(payload: Buffer): Promise<void>
7291
respondCallback(responseId: string, data: any): Promise<void>
7392
}

0 commit comments

Comments
 (0)