Queue the smallest backfill jobs first and show queued state
This commit is contained in:
@@ -158,9 +158,10 @@ Previews run after every walk:
|
|||||||
before their previews were cached. One job per chat groups every paused, done, or failed scrape
|
before their previews were cached. One job per chat groups every paused, done, or failed scrape
|
||||||
of that chat, so a paused-and-resumed scrape stays in one job. Jobs run one at a time, in
|
of that chat, so a paused-and-resumed scrape stays in one job. Jobs run one at a time, in
|
||||||
batches, and report pending/cached/failed counts, per-kind pending, throughput, and an ETA. The
|
batches, and report pending/cached/failed counts, per-kind pending, throughput, and an ETA. The
|
||||||
Bot tab drives them: **Start backfill**, per-job Start/Pause, and **Pause all**. On daemon boot
|
Bot tab drives them: **Start backfill**, per-job Start/Pause, and **Pause all**. Jobs with the
|
||||||
jobs start automatically when the Backfilling setting **Start automatically on daemon boot** is
|
least pending work start first, so small chats clear instead of waiting behind a long one; a job
|
||||||
on.
|
that is started but waiting for the queue reads `queued`. On daemon boot jobs start automatically
|
||||||
|
when the Backfilling setting **Start automatically on daemon boot** is on.
|
||||||
- Transient fetch failures keep the row pending and count up `preview_attempts`. After the
|
- Transient fetch failures keep the row pending and count up `preview_attempts`. After the
|
||||||
**Tries before giving up** setting (default 3) the row is marked `unreachable after N attempt(s)`,
|
**Tries before giving up** setting (default 3) the row is marked `unreachable after N attempt(s)`,
|
||||||
so dead hosts (Gfycat, Streamable) stop burning batches forever.
|
so dead hosts (Gfycat, Streamable) stop burning batches forever.
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ export interface BackfillMember {
|
|||||||
export interface BackfillJobStatus {
|
export interface BackfillJobStatus {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
guildId: string | null;
|
guildId: string | null;
|
||||||
state: "idle" | "running" | "paused" | "done";
|
/** `queued` means started, but another job holds the queue. */
|
||||||
|
state: "idle" | "queued" | "running" | "paused" | "done";
|
||||||
members: BackfillMember[];
|
members: BackfillMember[];
|
||||||
pending: number;
|
pending: number;
|
||||||
cached: number;
|
cached: number;
|
||||||
@@ -188,6 +189,8 @@ export class BackfillQueue {
|
|||||||
const groups = this.plan();
|
const groups = this.plan();
|
||||||
const jobs: BackfillJobStatus[] = [];
|
const jobs: BackfillJobStatus[] = [];
|
||||||
|
|
||||||
|
const anyClaimed = [...this.jobs.values()].some(candidate => candidate.claimed);
|
||||||
|
|
||||||
for (const [chatId, group] of groups) {
|
for (const [chatId, group] of groups) {
|
||||||
// Hide chats that are fully backfilled unless their job did work this session.
|
// Hide chats that are fully backfilled unless their job did work this session.
|
||||||
const tracked = this.jobs.get(chatId);
|
const tracked = this.jobs.get(chatId);
|
||||||
@@ -196,11 +199,13 @@ export class BackfillQueue {
|
|||||||
|
|
||||||
const perMinute = tracked?.perMinute ?? this.estimatedPerMinute(settings, gaps);
|
const perMinute = tracked?.perMinute ?? this.estimatedPerMinute(settings, gaps);
|
||||||
const etaMs = pending > 0 && perMinute > 0 ? Math.round((pending / perMinute) * 60_000) : null;
|
const etaMs = pending > 0 && perMinute > 0 ? Math.round((pending / perMinute) * 60_000) : null;
|
||||||
|
const state =
|
||||||
|
tracked?.state === "running" && anyClaimed && !tracked.claimed ? "queued" : (tracked?.state ?? "idle");
|
||||||
|
|
||||||
jobs.push({
|
jobs.push({
|
||||||
chatId,
|
chatId,
|
||||||
guildId: group.guildId,
|
guildId: group.guildId,
|
||||||
state: tracked?.state ?? "idle",
|
state,
|
||||||
members: group.members,
|
members: group.members,
|
||||||
pending,
|
pending,
|
||||||
cached: group.members.reduce((sum, member) => sum + member.cached, 0),
|
cached: group.members.reduce((sum, member) => sum + member.cached, 0),
|
||||||
@@ -280,11 +285,14 @@ export class BackfillQueue {
|
|||||||
return perRow > 0 ? 60_000 / perRow : 6000;
|
return perRow > 0 ? 60_000 / perRow : 6000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start every job with pending rows, or one chat's job. */
|
/** Start every job with pending rows, or one chat's job. Smallest jobs first: they finish. */
|
||||||
start(chatId?: string): void {
|
start(chatId?: string): void {
|
||||||
const status = this.list();
|
const status = this.list();
|
||||||
|
const order = chatId
|
||||||
|
? status.jobs
|
||||||
|
: [...status.jobs].sort((a, b) => a.pending - b.pending);
|
||||||
|
|
||||||
for (const job of status.jobs) {
|
for (const job of order) {
|
||||||
if (chatId && job.chatId !== chatId) continue;
|
if (chatId && job.chatId !== chatId) continue;
|
||||||
if (job.pending <= 0) continue;
|
if (job.pending <= 0) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -740,3 +740,8 @@
|
|||||||
color: color-mix(in srgb, var(--color-neutral-400) 55%, transparent);
|
color: color-mix(in srgb, var(--color-neutral-400) 55%, transparent);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vk-bot-state-queued {
|
||||||
|
background: color-mix(in srgb, var(--color-neutral-400) 18%, transparent);
|
||||||
|
color: var(--color-neutral-300);
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -615,7 +615,7 @@
|
|||||||
row.append(progress);
|
row.append(progress);
|
||||||
|
|
||||||
const actions = el("div", "vk-bot-job-actions");
|
const actions = el("div", "vk-bot-job-actions");
|
||||||
if (job.state === "running") {
|
if (job.state === "running" || job.state === "queued") {
|
||||||
actions.append(button("Pause", () => void backfillAction("pause", job.chatId)));
|
actions.append(button("Pause", () => void backfillAction("pause", job.chatId)));
|
||||||
} else if (job.pending > 0) {
|
} else if (job.pending > 0) {
|
||||||
actions.append(button("Start", () => void backfillAction("start", job.chatId)));
|
actions.append(button("Start", () => void backfillAction("start", job.chatId)));
|
||||||
|
|||||||
Reference in New Issue
Block a user