Skip to content

Commit 88b12bb

Browse files
fix(program): handle existing reuse/replace for address opens
1 parent 349ea2d commit 88b12bb

File tree

2 files changed

+43
-21
lines changed

2 files changed

+43
-21
lines changed

packages/programs/program/program/src/handler.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -157,33 +157,37 @@ export class Handler<T extends Manageable<any>> {
157157
// TODO add locks for store lifecycle, e.g. what happens if we try to open and close a store at the same time?
158158
let program = storeOrAddress as S;
159159
if (typeof storeOrAddress === "string") {
160+
const address = storeOrAddress.toString();
160161
try {
161-
if (this.items?.has(storeOrAddress.toString())) {
162-
const existing = await this.checkProcessExisting(
163-
storeOrAddress.toString(),
164-
program,
165-
options?.existing,
166-
);
167-
if (existing) {
162+
const existing = this.items.get(address);
163+
if (existing) {
164+
// Be defensive: stale handles shouldn't be returned from the cache.
165+
if (existing.closed) {
166+
this.items.delete(address);
167+
} else if (options?.existing === "reuse") {
168168
return existing as S;
169+
} else if (options?.existing === "replace") {
170+
await existing.close();
171+
} else {
172+
throw new Error(`Program at ${address} is already open`);
169173
}
170-
} else {
171-
program = (await this.properties.load(
172-
storeOrAddress,
173-
this.properties.client.services.blocks,
174-
options,
175-
)) as S; // TODO fix typings
176-
177-
if (!this.properties.shouldMonitor(program)) {
178-
if (!program) {
179-
throw new Error(
180-
"Failed to resolve program with address: " + storeOrAddress,
181-
);
182-
}
174+
}
175+
176+
program = (await this.properties.load(
177+
address,
178+
this.properties.client.services.blocks,
179+
options,
180+
)) as S; // TODO fix typings
181+
182+
if (!this.properties.shouldMonitor(program)) {
183+
if (!program) {
183184
throw new Error(
184-
`Failed to open program because program is of type ${program?.constructor.name} `,
185+
"Failed to resolve program with address: " + address,
185186
);
186187
}
188+
throw new Error(
189+
`Failed to open program because program is of type ${program?.constructor.name} `,
190+
);
187191
}
188192
} catch (error) {
189193
logger.error(

packages/programs/program/program/test/handler.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,24 @@ describe(`shared`, () => {
4646
);
4747
});
4848

49+
it("reuse open by address returns existing instance", async () => {
50+
const db1 = await client.open(new TestProgram());
51+
const db2 = await client.open(db1.address, { existing: "reuse" });
52+
expect(db2).equal(db1);
53+
});
54+
55+
it("replace open by address closes old and reopens", async () => {
56+
const db1 = await client.open(new TestProgram());
57+
const address = db1.address;
58+
59+
const db2 = await client.open(address, { existing: "replace" });
60+
61+
expect(db1.closed).to.be.true;
62+
expect(db2.closed).to.be.false;
63+
expect(db2.address).to.equal(address);
64+
expect(db2).to.not.equal(db1);
65+
});
66+
4967
it("is open on open", async () => {
5068
const instance = new TestProgram();
5169
const openFn = instance.open.bind(instance);

0 commit comments

Comments
 (0)