refactor(queue): share drain helpers across announce and reply
This commit is contained in:
parent
78220db2be
commit
dacb3d1aa2
@ -8,9 +8,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
applyQueueRuntimeSettings,
|
applyQueueRuntimeSettings,
|
||||||
applyQueueDropPolicy,
|
applyQueueDropPolicy,
|
||||||
|
beginQueueDrain,
|
||||||
buildCollectPrompt,
|
buildCollectPrompt,
|
||||||
clearQueueSummaryState,
|
clearQueueSummaryState,
|
||||||
drainCollectItemIfNeeded,
|
drainCollectQueueStep,
|
||||||
drainNextQueueItem,
|
drainNextQueueItem,
|
||||||
hasCrossChannelItems,
|
hasCrossChannelItems,
|
||||||
previewQueueSummaryPrompt,
|
previewQueueSummaryPrompt,
|
||||||
@ -97,33 +98,35 @@ function getAnnounceQueue(
|
|||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasAnnounceCrossChannelItems(items: AnnounceQueueItem[]): boolean {
|
||||||
|
return hasCrossChannelItems(items, (item) => {
|
||||||
|
if (!item.origin) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!item.originKey) {
|
||||||
|
return { cross: true };
|
||||||
|
}
|
||||||
|
return { key: item.originKey };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function scheduleAnnounceDrain(key: string) {
|
function scheduleAnnounceDrain(key: string) {
|
||||||
const queue = ANNOUNCE_QUEUES.get(key);
|
const queue = beginQueueDrain(ANNOUNCE_QUEUES, key);
|
||||||
if (!queue || queue.draining) {
|
if (!queue) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queue.draining = true;
|
|
||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
let forceIndividualCollect = false;
|
const collectState = { forceIndividualCollect: false };
|
||||||
while (queue.items.length > 0 || queue.droppedCount > 0) {
|
for (;;) {
|
||||||
|
if (queue.items.length === 0 && queue.droppedCount === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
await waitForQueueDebounce(queue);
|
await waitForQueueDebounce(queue);
|
||||||
if (queue.mode === "collect") {
|
if (queue.mode === "collect") {
|
||||||
const isCrossChannel = hasCrossChannelItems(queue.items, (item) => {
|
const collectDrainResult = await drainCollectQueueStep({
|
||||||
if (!item.origin) {
|
collectState,
|
||||||
return {};
|
isCrossChannel: hasAnnounceCrossChannelItems(queue.items),
|
||||||
}
|
|
||||||
if (!item.originKey) {
|
|
||||||
return { cross: true };
|
|
||||||
}
|
|
||||||
return { key: item.originKey };
|
|
||||||
});
|
|
||||||
const collectDrainResult = await drainCollectItemIfNeeded({
|
|
||||||
forceIndividualCollect,
|
|
||||||
isCrossChannel,
|
|
||||||
setForceIndividualCollect: (next) => {
|
|
||||||
forceIndividualCollect = next;
|
|
||||||
},
|
|
||||||
items: queue.items,
|
items: queue.items,
|
||||||
run: async (item) => await queue.send(item),
|
run: async (item) => await queue.send(item),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { defaultRuntime } from "../../../runtime.js";
|
import { defaultRuntime } from "../../../runtime.js";
|
||||||
import {
|
import {
|
||||||
buildCollectPrompt,
|
buildCollectPrompt,
|
||||||
|
beginQueueDrain,
|
||||||
clearQueueSummaryState,
|
clearQueueSummaryState,
|
||||||
drainCollectItemIfNeeded,
|
drainCollectQueueStep,
|
||||||
drainNextQueueItem,
|
drainNextQueueItem,
|
||||||
hasCrossChannelItems,
|
hasCrossChannelItems,
|
||||||
previewQueueSummaryPrompt,
|
previewQueueSummaryPrompt,
|
||||||
@ -16,14 +17,13 @@ export function scheduleFollowupDrain(
|
|||||||
key: string,
|
key: string,
|
||||||
runFollowup: (run: FollowupRun) => Promise<void>,
|
runFollowup: (run: FollowupRun) => Promise<void>,
|
||||||
): void {
|
): void {
|
||||||
const queue = FOLLOWUP_QUEUES.get(key);
|
const queue = beginQueueDrain(FOLLOWUP_QUEUES, key);
|
||||||
if (!queue || queue.draining) {
|
if (!queue) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queue.draining = true;
|
|
||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
let forceIndividualCollect = false;
|
const collectState = { forceIndividualCollect: false };
|
||||||
while (queue.items.length > 0 || queue.droppedCount > 0) {
|
while (queue.items.length > 0 || queue.droppedCount > 0) {
|
||||||
await waitForQueueDebounce(queue);
|
await waitForQueueDebounce(queue);
|
||||||
if (queue.mode === "collect") {
|
if (queue.mode === "collect") {
|
||||||
@ -50,12 +50,9 @@ export function scheduleFollowupDrain(
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const collectDrainResult = await drainCollectItemIfNeeded({
|
const collectDrainResult = await drainCollectQueueStep({
|
||||||
forceIndividualCollect,
|
collectState,
|
||||||
isCrossChannel,
|
isCrossChannel,
|
||||||
setForceIndividualCollect: (next) => {
|
|
||||||
forceIndividualCollect = next;
|
|
||||||
},
|
|
||||||
items: queue.items,
|
items: queue.items,
|
||||||
run: runFollowup,
|
run: runFollowup,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -132,6 +132,18 @@ export function waitForQueueDebounce(queue: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function beginQueueDrain<T extends { draining: boolean }>(
|
||||||
|
map: Map<string, T>,
|
||||||
|
key: string,
|
||||||
|
): T | undefined {
|
||||||
|
const queue = map.get(key);
|
||||||
|
if (!queue || queue.draining) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
queue.draining = true;
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
export async function drainNextQueueItem<T>(
|
export async function drainNextQueueItem<T>(
|
||||||
items: T[],
|
items: T[],
|
||||||
run: (item: T) => Promise<void>,
|
run: (item: T) => Promise<void>,
|
||||||
@ -162,6 +174,23 @@ export async function drainCollectItemIfNeeded<T>(params: {
|
|||||||
return drained ? "drained" : "empty";
|
return drained ? "drained" : "empty";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function drainCollectQueueStep<T>(params: {
|
||||||
|
collectState: { forceIndividualCollect: boolean };
|
||||||
|
isCrossChannel: boolean;
|
||||||
|
items: T[];
|
||||||
|
run: (item: T) => Promise<void>;
|
||||||
|
}): Promise<"skipped" | "drained" | "empty"> {
|
||||||
|
return await drainCollectItemIfNeeded({
|
||||||
|
forceIndividualCollect: params.collectState.forceIndividualCollect,
|
||||||
|
isCrossChannel: params.isCrossChannel,
|
||||||
|
setForceIndividualCollect: (next) => {
|
||||||
|
params.collectState.forceIndividualCollect = next;
|
||||||
|
},
|
||||||
|
items: params.items,
|
||||||
|
run: params.run,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function buildQueueSummaryPrompt(params: {
|
export function buildQueueSummaryPrompt(params: {
|
||||||
state: QueueSummaryState;
|
state: QueueSummaryState;
|
||||||
noun: string;
|
noun: string;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user