fix: require idle workers for submit
This commit is contained in:
@@ -20,15 +20,7 @@ const base = {
|
||||
hasAttachments: false,
|
||||
};
|
||||
|
||||
Deno.test("running Composer enables Queue Submit and Notify but not immediate Submit", () => {
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
delivery: "queue",
|
||||
workerState: "running",
|
||||
}),
|
||||
true,
|
||||
);
|
||||
Deno.test("running Composer enables Notify but not Submit", () => {
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
@@ -47,16 +39,8 @@ Deno.test("running Composer enables Queue Submit and Notify but not immediate Su
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("running Queue Submit and Notify dispatch their protocol methods", () => {
|
||||
Deno.test("running Notify dispatches its protocol method", () => {
|
||||
const sent: string[] = [];
|
||||
assertEquals(
|
||||
sendComposerDelivery(
|
||||
{ ...base, delivery: "queue", workerState: "running" },
|
||||
"submit",
|
||||
(method) => sent.push(method),
|
||||
),
|
||||
true,
|
||||
);
|
||||
assertEquals(
|
||||
sendComposerDelivery(
|
||||
{ ...base, delivery: "notify", workerState: "running" },
|
||||
@@ -65,10 +49,10 @@ Deno.test("running Queue Submit and Notify dispatch their protocol methods", ()
|
||||
),
|
||||
true,
|
||||
);
|
||||
assertEquals(sent.join(","), "submit,notify");
|
||||
assertEquals(sent.join(","), "notify");
|
||||
});
|
||||
|
||||
Deno.test("idle Composer enables only immediate Submit", () => {
|
||||
Deno.test("idle Composer enables only Submit", () => {
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
@@ -77,14 +61,6 @@ Deno.test("idle Composer enables only immediate Submit", () => {
|
||||
}),
|
||||
true,
|
||||
);
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
delivery: "queue",
|
||||
workerState: "idle",
|
||||
}),
|
||||
false,
|
||||
);
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
@@ -95,11 +71,30 @@ Deno.test("idle Composer enables only immediate Submit", () => {
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("running delivery remains fenced by protocol, send state, and payload kind", () => {
|
||||
Deno.test("paused Composer enables neither Submit nor Notify", () => {
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
delivery: "queue",
|
||||
delivery: "submit",
|
||||
workerState: "paused",
|
||||
}),
|
||||
false,
|
||||
);
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
delivery: "notify",
|
||||
workerState: "paused",
|
||||
}),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("running Notify remains fenced by protocol, send state, and payload kind", () => {
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
delivery: "notify",
|
||||
workerState: "running",
|
||||
protocolOpen: false,
|
||||
}),
|
||||
@@ -123,14 +118,4 @@ Deno.test("running delivery remains fenced by protocol, send state, and payload
|
||||
}),
|
||||
false,
|
||||
);
|
||||
assertEquals(
|
||||
canDeliverComposerDraft({
|
||||
...base,
|
||||
delivery: "queue",
|
||||
workerState: "running",
|
||||
hasText: false,
|
||||
hasAttachments: true,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type ComposerDelivery = "submit" | "queue" | "notify";
|
||||
export type ComposerDelivery = "submit" | "notify";
|
||||
|
||||
export type ComposerDeliveryState = {
|
||||
delivery: ComposerDelivery;
|
||||
@@ -11,7 +11,7 @@ export type ComposerDeliveryState = {
|
||||
|
||||
/**
|
||||
* Resolve whether the current Composer draft can use one delivery action.
|
||||
* Immediate Submit is idle-only; Queue and Notify are running-only.
|
||||
* Immediate Submit is idle-only; Notify is running-only.
|
||||
*/
|
||||
export function canDeliverComposerDraft(state: ComposerDeliveryState): boolean {
|
||||
if (!state.protocolOpen || state.sending) return false;
|
||||
@@ -20,8 +20,6 @@ export function canDeliverComposerDraft(state: ComposerDeliveryState): boolean {
|
||||
switch (state.delivery) {
|
||||
case "submit":
|
||||
return state.workerState === "idle" && hasInput;
|
||||
case "queue":
|
||||
return state.workerState === "running" && hasInput;
|
||||
case "notify":
|
||||
return state.workerState === "running" && state.hasText &&
|
||||
!state.hasAttachments;
|
||||
|
||||
@@ -1239,7 +1239,7 @@ Deno.test("Web Console switches main and direct SubWorker views from the Tasks r
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Web Console uses Notify while running and exposes durable pending controls", async () => {
|
||||
Deno.test("Web Console uses Notify while running and keeps recovery pending controls", async () => {
|
||||
const consolePage = await Deno.readTextFile(
|
||||
new URL(
|
||||
"./../../../routes/w/[workspaceId]/workers/[workerRef]/console/+page.svelte",
|
||||
@@ -1257,12 +1257,8 @@ Deno.test("Web Console uses Notify while running and exposes durable pending con
|
||||
'method: "cancel_pending_submission"',
|
||||
'method: "clear_pending_submissions"',
|
||||
'method: "continue_pending"',
|
||||
"handleQueueSubmit",
|
||||
"handleNotifySubmit",
|
||||
'submitDraft(composerInputElement?.snapshot() ?? draft, "queue")',
|
||||
"disabled={!canQueueDraft}",
|
||||
"disabled={!canNotifyDraft}",
|
||||
">Queue Submit</button>",
|
||||
">Notify</button>",
|
||||
]
|
||||
) {
|
||||
@@ -1272,6 +1268,13 @@ Deno.test("Web Console uses Notify while running and exposes durable pending con
|
||||
);
|
||||
}
|
||||
|
||||
assert(
|
||||
!consolePage.includes("handleQueueSubmit") &&
|
||||
!consolePage.includes(">Queue Submit</button>") &&
|
||||
!consolePage.includes('delivery: "queue"'),
|
||||
"running Console must not offer Submit queueing; callers should use Notify",
|
||||
);
|
||||
|
||||
const userCase = consolePage.slice(
|
||||
consolePage.indexOf('case "user":'),
|
||||
consolePage.indexOf('case "compact":'),
|
||||
|
||||
@@ -269,16 +269,6 @@
|
||||
hasAttachments: draftHasAttachments,
|
||||
}),
|
||||
);
|
||||
const canQueueDraft = $derived(
|
||||
canDeliverComposerDraft({
|
||||
delivery: "queue",
|
||||
workerState,
|
||||
protocolOpen: protocolState === "open",
|
||||
sending,
|
||||
hasText: draftHasText,
|
||||
hasAttachments: draftHasAttachments,
|
||||
}),
|
||||
);
|
||||
const canNotifyDraft = $derived(
|
||||
canDeliverComposerDraft({
|
||||
delivery: "notify",
|
||||
@@ -729,10 +719,6 @@
|
||||
void submitDraft(composerInputElement?.snapshot() ?? draft);
|
||||
}
|
||||
|
||||
function handleQueueSubmit() {
|
||||
void submitDraft(composerInputElement?.snapshot() ?? draft, "queue");
|
||||
}
|
||||
|
||||
function handleNotifySubmit() {
|
||||
void submitDraft(composerInputElement?.snapshot() ?? draft, "notify");
|
||||
}
|
||||
@@ -842,7 +828,7 @@
|
||||
) {
|
||||
if (delivery === "notify" && attachments.length > 0) {
|
||||
composerNotice = null;
|
||||
sendError = "Notify accepts text only; remove attachments or queue a Submit.";
|
||||
sendError = "Notify accepts text only; remove attachments or wait until the Worker is idle to Submit.";
|
||||
return;
|
||||
}
|
||||
const incompleteAttachment = attachments.find((attachment) =>
|
||||
@@ -2151,11 +2137,6 @@
|
||||
</div>
|
||||
<div class="composer-actions">
|
||||
{#if workerRunning}
|
||||
<button
|
||||
type="button"
|
||||
disabled={!canQueueDraft}
|
||||
onclick={handleQueueSubmit}
|
||||
>Queue Submit</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!canNotifyDraft}
|
||||
|
||||
Reference in New Issue
Block a user