|
@@ -58,19 +58,23 @@ interface WaitForBookReadyOptions {
|
|
|
readonly waitImpl?: (ms: number) => Promise<void>;
|
|
readonly waitImpl?: (ms: number) => Promise<void>;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const DEFAULT_BOOK_READY_MAX_ATTEMPTS = 120;
|
|
|
|
|
+const DEFAULT_BOOK_READY_DELAY_MS = 250;
|
|
|
|
|
+
|
|
|
export async function waitForBookReady(
|
|
export async function waitForBookReady(
|
|
|
bookId: string,
|
|
bookId: string,
|
|
|
options: WaitForBookReadyOptions = {},
|
|
options: WaitForBookReadyOptions = {},
|
|
|
): Promise<void> {
|
|
): Promise<void> {
|
|
|
const fetchBook = options.fetchBook ?? ((id: string) => fetchJson(`/books/${id}`));
|
|
const fetchBook = options.fetchBook ?? ((id: string) => fetchJson(`/books/${id}`));
|
|
|
const fetchStatus = options.fetchStatus ?? ((id: string) => fetchJson<{ status: string; error?: string }>(`/books/${id}/create-status`));
|
|
const fetchStatus = options.fetchStatus ?? ((id: string) => fetchJson<{ status: string; error?: string }>(`/books/${id}/create-status`));
|
|
|
- const maxAttempts = options.maxAttempts ?? 20;
|
|
|
|
|
- const delayMs = options.delayMs ?? 150;
|
|
|
|
|
|
|
+ const maxAttempts = options.maxAttempts ?? DEFAULT_BOOK_READY_MAX_ATTEMPTS;
|
|
|
|
|
+ const delayMs = options.delayMs ?? DEFAULT_BOOK_READY_DELAY_MS;
|
|
|
const waitImpl = options.waitImpl ?? ((ms: number) => new Promise<void>((resolve) => {
|
|
const waitImpl = options.waitImpl ?? ((ms: number) => new Promise<void>((resolve) => {
|
|
|
setTimeout(resolve, ms);
|
|
setTimeout(resolve, ms);
|
|
|
}));
|
|
}));
|
|
|
|
|
|
|
|
let lastError: unknown;
|
|
let lastError: unknown;
|
|
|
|
|
+ let lastKnownStatus: string | undefined;
|
|
|
|
|
|
|
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
|
try {
|
|
try {
|
|
@@ -80,6 +84,7 @@ export async function waitForBookReady(
|
|
|
lastError = error;
|
|
lastError = error;
|
|
|
try {
|
|
try {
|
|
|
const status = await fetchStatus(bookId);
|
|
const status = await fetchStatus(bookId);
|
|
|
|
|
+ lastKnownStatus = status.status;
|
|
|
if (status.status === "error") {
|
|
if (status.status === "error") {
|
|
|
throw new Error(status.error ?? `Book "${bookId}" failed to create`);
|
|
throw new Error(status.error ?? `Book "${bookId}" failed to create`);
|
|
|
}
|
|
}
|
|
@@ -89,12 +94,19 @@ export async function waitForBookReady(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if (attempt === maxAttempts - 1) {
|
|
if (attempt === maxAttempts - 1) {
|
|
|
|
|
+ if (lastKnownStatus === "creating") {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
throw error;
|
|
throw error;
|
|
|
}
|
|
}
|
|
|
await waitImpl(delayMs);
|
|
await waitImpl(delayMs);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (lastKnownStatus === "creating") {
|
|
|
|
|
+ throw new Error(`Book "${bookId}" is still being created. Wait a moment and refresh.`);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
throw lastError instanceof Error ? lastError : new Error(`Book "${bookId}" was not ready`);
|
|
throw lastError instanceof Error ? lastError : new Error(`Book "${bookId}" was not ready`);
|
|
|
}
|
|
}
|
|
|
|
|
|