mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(p2): archiving a viewed session shows no error and starts no refused worker
Archiving from the session sheet navigates away first, which unmounted SessionOptions and released its Sessions reference; Chord cancels a released reference's calls, so the archive call rejected with "p2.sessions: released", shown as the composer toast over the owner-notice lane. The archive now holds a reference of its own until it is done, and the server runs its steps in a root of its own. The archive stopped the worker with Hosts.stop, which restarts it for its holders: the page's lingering conversation started a worker the archived session refused (resolve_failed, "Worker: Session is archived" notice). SessionWorkerControl.suspend stops it and leaves its holders suspended until a restore (retry) or their release; archive, a failed fork's archived copy and an archived session's index rebuild use it.
This commit is contained in:
parent
15a5114599
commit
0a730c8a76
9 changed files with 149 additions and 14 deletions
|
|
@ -137,7 +137,7 @@ export default defineFacet((host) => {
|
|||
} finally {
|
||||
if (archived) {
|
||||
await archivedStarts.end({ session }, ctx);
|
||||
await hosts.stop({ session }, ctx);
|
||||
await server().workers.suspend(session);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
// Native catalog operations beneath the copied mobile Session sheet.
|
||||
import { BACKGROUND_CONTEXT } from "@p2/app/v1";
|
||||
import { BACKGROUND_CONTEXT, liveIn, whenLive } from "@p2/app/v1";
|
||||
import {
|
||||
closeLayers,
|
||||
conversationRoute,
|
||||
MoreIcon,
|
||||
openLayer,
|
||||
useComposerState,
|
||||
useHost,
|
||||
useNavigation,
|
||||
useObject,
|
||||
useReadable,
|
||||
|
|
@ -16,7 +17,8 @@ import { directoryPickerLayer } from "../envs/contract.web.tsx";
|
|||
import { Sessions } from "./contract.ts";
|
||||
import { SessionSheet } from "./SessionSheet.tsx";
|
||||
export function SessionOptions() {
|
||||
const nav = useNavigation(),
|
||||
const host = useHost(),
|
||||
nav = useNavigation(),
|
||||
route = useRoute();
|
||||
const service = useObject(Sessions, {}, { variant: "owner" }),
|
||||
rows = useReadable(service?.sessions);
|
||||
|
|
@ -47,7 +49,14 @@ export function SessionOptions() {
|
|||
onArchive={() => {
|
||||
closeLayers();
|
||||
void nav.replace(conversationRoute(route, undefined));
|
||||
perform(service?.archive({ id: session.id }, BACKGROUND_CONTEXT));
|
||||
// Leaving the session unmounts this view and releases `service`, which cancels its calls: the
|
||||
// archive holds a reference of its own until it is done.
|
||||
const archiving = host.hold(Sessions, {}, BACKGROUND_CONTEXT);
|
||||
perform(
|
||||
whenLive(archiving)
|
||||
.then(() => liveIn(archiving, "owner")?.archive({ id: session.id }, BACKGROUND_CONTEXT))
|
||||
.finally(() => archiving.release()),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
serveKeyed,
|
||||
WorkerBoundary,
|
||||
} from "@p2/app/v1";
|
||||
import { Hosts, Server, serverOf, WorkerInitValues } from "@p2/app/v1/server";
|
||||
import { Server, serverOf, WorkerInitValues } from "@p2/app/v1/server";
|
||||
import { EnvManagers, EnvService } from "../envs/contract.ts";
|
||||
import { ModelConfig, ModelResources } from "../models/contract.ts";
|
||||
import { ChildStore } from "../subagents/contract.ts";
|
||||
|
|
@ -236,7 +236,6 @@ export default defineFacet((host) => {
|
|||
return { variant: "guest", members: { sessions: sessionsView } };
|
||||
}
|
||||
if (!isOwner(principal)) throw forbidden("sessions are owner-only");
|
||||
const hosts = self.get(Hosts, {});
|
||||
const lifecycleOf = serverOf(self);
|
||||
const models = self.get(ModelConfig, {});
|
||||
const resources = nativeOf(self, ModelResources, "The model configuration");
|
||||
|
|
@ -361,7 +360,9 @@ export default defineFacet((host) => {
|
|||
} catch (error) {
|
||||
if (created) {
|
||||
await catalog.update({ id: copy, archived: true }, ctx).catch(() => {});
|
||||
await hosts.stop({ session: copy }, ctx).catch(() => {});
|
||||
await lifecycleOf()
|
||||
.workers.suspend(copy)
|
||||
.catch(() => {});
|
||||
} else await removeSessionCopy(dataDir, copy);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -376,10 +377,13 @@ export default defineFacet((host) => {
|
|||
await catalog.update({ id, pinned }, ctx);
|
||||
return null;
|
||||
},
|
||||
archive: async ({ id }, ctx) => {
|
||||
await catalog.update({ id, archived: true }, ctx);
|
||||
// Archive stops the worker whatever it is doing; its storage and history stay.
|
||||
await hosts.stop({ session: id }, ctx);
|
||||
archive: async ({ id }) => {
|
||||
await lifecycle(async (root) => {
|
||||
await catalog.update({ id, archived: true }, root);
|
||||
// Archive stops the worker whatever it is doing; its storage and history stay. Its holders (a page's
|
||||
// lingering conversation) wait for a restore rather than start a worker the archive refuses.
|
||||
await lifecycleOf().workers.suspend(id);
|
||||
});
|
||||
return null;
|
||||
},
|
||||
restore: async ({ id }, ctx) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue