Keep bunext sitemap alive while sitemap exports query the DB

Bun's SQL client (mariadb/mysql adapters, Bun 1.3.14) doesn't keep the
event loop alive for a query on an idle connection, so a second dynamic
route's sitemap export querying the DB made the command exit silently.
Hold the loop open with a timer during generation, and log what a stuck
run is waiting on.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-15 09:00:40 +01:00
co-authored by Claude Opus 5.5
parent 23a309005a
commit 40c17f903e
7 changed files with 153 additions and 37 deletions
+14 -2
View File
@@ -5,9 +5,10 @@ import { log } from "../../utils/log";
import grabDirNames from "../../utils/grab-dir-names";
import grabConfig from "../../functions/grab-config";
import grabConstants from "../../utils/grab-constants";
import { generateSitemapFiles } from "../../utils/generate-sitemap";
import { generateSitemapFiles, grabPendingSitemapTask, } from "../../utils/generate-sitemap";
import { grabPageLastmodFile } from "../../utils/page-lastmod-record";
import generateRobotsTxt, { RobotsTxtGeneratedMarker, } from "../../utils/generate-robots-txt";
const SitemapStillWaitingInterval = 30_000;
export default function () {
return new Command("sitemap")
.description("Generate sitemap.xml and robots.txt from the pages directory")
@@ -39,12 +40,23 @@ export default function () {
throw new Error(`\`sitemap.chunks_dir\` must be inside public/ ` +
`so the chunks are served.`);
}
// Bun exits silently (code 0) when the event loop empties
// while a promise is pending. Bun's SQL client (mariadb /
// mysql adapters, Bun 1.3.14) doesn't keep the loop alive
// for a query on a connection that has gone idle, so a
// second `sitemap` export querying the DB would end the
// process mid-generation. Hold the loop open with a timer,
// which also reports what a genuinely stuck run waits on.
const keep_alive = setInterval(() => {
log.warn(`Still waiting on ` +
`${grabPendingSitemapTask() || "sitemap generation"}...`);
}, SitemapStillWaitingInterval);
const { sitemap, chunks, url_count } = await generateSitemapFiles({
...sitemap_config,
origin: options.origin || sitemap_config.origin,
chunk_size,
chunks_url_path: chunks_public_path,
});
}).finally(() => clearInterval(keep_alive));
// Remove chunks from a previous, larger sitemap
if (existsSync(chunks_dir_path)) {
for (const file of readdirSync(chunks_dir_path)) {