Skip to content

Commit 6d54739

Browse files
committed
chore: throw error if attempting to create actor multiple times
1 parent ffdf65d commit 6d54739

File tree

7 files changed

+55
-0
lines changed

7 files changed

+55
-0
lines changed

packages/actor-core/src/actor/errors.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,16 @@ export class ActorNotFound extends ActorError {
254254
}
255255
}
256256

257+
export class ActorAlreadyExists extends ActorError {
258+
constructor(name: string, key: string[]) {
259+
super(
260+
"actor_already_exists",
261+
`Actor already exists with name "${name}" and key ${JSON.stringify(key)}`,
262+
{ public: true }
263+
);
264+
}
265+
}
266+
257267
export class ProxyError extends ActorError {
258268
constructor(operation: string, error?: unknown) {
259269
super(

packages/actor-core/src/test/driver/manager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import type {
66
GetWithKeyInput,
77
ManagerDriver,
88
} from "@/driver-helpers/mod";
9+
import { ActorAlreadyExists } from "@/actor/errors";
910
import type { TestGlobalState } from "./global-state";
11+
import * as crypto from "node:crypto";
1012
import { ManagerInspector } from "@/inspector/manager";
1113
import type { ActorCoreApp } from "@/app/mod";
1214

@@ -117,6 +119,12 @@ export class TestManagerDriver implements ManagerDriver {
117119
name,
118120
key,
119121
}: CreateActorInput): Promise<CreateActorOutput> {
122+
// Check if actor with the same name and key already exists
123+
const existingActor = await this.getWithKey({ name, key });
124+
if (existingActor) {
125+
throw new ActorAlreadyExists(name, key);
126+
}
127+
120128
const actorId = crypto.randomUUID();
121129
this.#state.createActor(actorId, name, key);
122130

packages/drivers/file-system/src/manager.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
GetWithKeyInput,
88
ManagerDriver,
99
} from "actor-core/driver-helpers";
10+
import { ActorAlreadyExists } from "actor-core/actor/errors";
1011
import { logger } from "./log";
1112
import type { FileSystemGlobalState } from "./global-state";
1213
import type { ActorCoreApp } from "actor-core";
@@ -95,6 +96,12 @@ export class FileSystemManagerDriver implements ManagerDriver {
9596
name,
9697
key,
9798
}: CreateActorInput): Promise<CreateActorOutput> {
99+
// Check if actor with the same name and key already exists
100+
const existingActor = await this.getWithKey({ name, key });
101+
if (existingActor) {
102+
throw new ActorAlreadyExists(name, key);
103+
}
104+
98105
const actorId = crypto.randomUUID();
99106
await this.#state.createActor(actorId, name, key);
100107

packages/drivers/memory/src/manager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import type {
66
GetWithKeyInput,
77
ManagerDriver,
88
} from "actor-core/driver-helpers";
9+
import { ActorAlreadyExists } from "actor-core/actor/errors";
910
import type { MemoryGlobalState } from "./global-state";
11+
import * as crypto from "node:crypto";
1012
import { ManagerInspector } from "actor-core/inspector";
1113
import type { ActorCoreApp } from "actor-core";
1214

@@ -86,6 +88,12 @@ export class MemoryManagerDriver implements ManagerDriver {
8688
name,
8789
key,
8890
}: CreateActorInput): Promise<CreateActorOutput> {
91+
// Check if actor with the same name and key already exists
92+
const existingActor = await this.getWithKey({ name, key });
93+
if (existingActor) {
94+
throw new ActorAlreadyExists(name, key);
95+
}
96+
8997
const actorId = crypto.randomUUID();
9098
this.#state.createActor(actorId, name, key);
9199

packages/drivers/redis/src/manager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import type {
66
GetWithKeyInput,
77
ManagerDriver,
88
} from "actor-core/driver-helpers";
9+
import { ActorAlreadyExists } from "actor-core/actor/errors";
910
import type Redis from "ioredis";
11+
import * as crypto from "node:crypto";
1012
import { KEYS } from "./keys";
1113
import { ManagerInspector } from "actor-core/inspector";
1214
import type { ActorCoreApp } from "actor-core";
@@ -93,6 +95,12 @@ export class RedisManagerDriver implements ManagerDriver {
9395
name,
9496
key,
9597
}: CreateActorInput): Promise<CreateActorOutput> {
98+
// Check if actor with the same name and key already exists
99+
const existingActor = await this.getWithKey({ name, key });
100+
if (existingActor) {
101+
throw new ActorAlreadyExists(name, key);
102+
}
103+
96104
const actorId = crypto.randomUUID();
97105
const actorKeyRedisKey = this.#generateActorKeyRedisKey(name, key);
98106

packages/platforms/cloudflare-workers/src/manager-driver.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
CreateActorInput,
66
GetActorOutput,
77
} from "actor-core/driver-helpers";
8+
import { ActorAlreadyExists } from "actor-core/actor/errors";
89
import { Bindings } from "./mod";
910
import { logger } from "./log";
1011
import { serializeNameAndKey, serializeKey } from "./util";
@@ -112,6 +113,12 @@ export class CloudflareWorkersManagerDriver implements ManagerDriver {
112113
if (!c) throw new Error("Missing Hono context");
113114
const log = logger();
114115

116+
// Check if actor with the same name and key already exists
117+
const existingActor = await this.getWithKey({ c, name, key });
118+
if (existingActor) {
119+
throw new ActorAlreadyExists(name, key);
120+
}
121+
115122
// Create a deterministic ID from the actor name and key
116123
// This ensures that actors with the same name and key will have the same ID
117124
const nameKeyString = serializeNameAndKey(name, key);

packages/platforms/rivet/src/manager-driver.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { assertUnreachable } from "actor-core/utils";
2+
import { ActorAlreadyExists } from "actor-core/actor/errors";
23
import type {
34
ManagerDriver,
45
GetForIdInput,
@@ -121,6 +122,12 @@ export class RivetManagerDriver implements ManagerDriver {
121122
key,
122123
region,
123124
}: CreateActorInput): Promise<GetActorOutput> {
125+
// Check if actor with the same name and key already exists
126+
const existingActor = await this.getWithKey({ name, key });
127+
if (existingActor) {
128+
throw new ActorAlreadyExists(name, key);
129+
}
130+
124131
// Create the actor request
125132
let actorLogLevel: string | undefined = undefined;
126133
if (typeof Deno !== "undefined") {

0 commit comments

Comments
 (0)