Truncate noisy build-failure output, fix the recurring terrain death
CI / check (push) Failing after 4s
CI / deploy (push) Skipped

The web UI was showing a raw ~500k-character stdout/stderr dump on a
failed build — go-pmtiles' extract logs one progress line per chunk,
which is fine on a terminal (it overwrites itself) but not captured
non-interactively. command_output now keeps just the tail, and the
status line renders it with preserved line breaks in a scrollable box
instead of one unreadable blob.

Root cause of the actual failure (terrain build dying ~11 minutes in
with an HTTP/2 stream reset): go-pmtiles' default --overfetch=0.05
merged this multi-country planet.pmtiles extract into a single ~60GB
request with no way to resume after a dropped stream. --overfetch=0
splits it into many smaller requests instead.
This commit is contained in:
randy committed 2026-09-12 19:41:45 +02:00
1 parent 237e5b2e54
commit f18e5c19d3
5 files changed
+92 -13

No files matched your search

+17 -9
View File
@@ -206,23 +206,31 @@ class DataFileRow {
this._refreshStatus();
}
// Single place that writes to _statusEl, so the error styling (pre-wrap,
// scrollable, red — see style.css) never stays stuck on once a build's
// failure message has scrolled past into a normal status line.
_setStatus(text, isError = false) {
this._statusEl.textContent = text;
this._statusEl.classList.toggle("offline-data-panel__status--error", isError);
}
async _refreshStatus() {
let data;
try {
data = await (await fetch(this._statusUrl)).json();
} catch {
this._statusEl.textContent = "Could not check status.";
this._setStatus("Could not check status.");
return;
}
if (!data.available) {
this._statusEl.textContent = "Not generated yet.";
this._setStatus("Not generated yet.");
this._deleteButton.hidden = true;
return;
}
const updated = new Date(data.mtime).toLocaleString([], { dateStyle: "short", timeStyle: "short" });
this._statusEl.textContent = `${formatBytes(data.size)} · updated ${updated}${this._formatMeta(data.meta)}`;
this._setStatus(`${formatBytes(data.size)} · updated ${updated}${this._formatMeta(data.meta)}`);
this._deleteButton.hidden = !isLoggedIn();
this._checkUpdate();
}
@@ -274,7 +282,7 @@ class DataFileRow {
// Called by OfflineDataControl once RegionPicker's Apply has saved a
// new selection — not tied to a button of this row's own.
async triggerBuild() {
this._statusEl.textContent = "Checking…";
this._setStatus("Checking…");
try {
// false (not null/true — see offline_update_available? in
// pmtiles_builder.rb) means the just-saved selection matches what's
@@ -291,17 +299,17 @@ class DataFileRow {
// couldn't tell — fall through and build rather than silently skip
}
this._statusEl.textContent = "Starting…";
this._setStatus("Starting…");
try {
const response = await fetch(this._buildUrl, { method: "POST" });
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.error || `build failed: ${response.status}`);
} catch (err) {
this._statusEl.textContent = err.message;
this._setStatus(err.message, true);
return;
}
this._statusEl.textContent = "Building…";
this._setStatus("Building…");
this._poll();
}
@@ -318,13 +326,13 @@ class DataFileRow {
}
if (status.state === "running") {
this._statusEl.textContent = formatRunning(status);
this._setStatus(formatRunning(status));
this._poll();
return;
}
if (status.state === "error") {
this._statusEl.textContent = `Build failed: ${status.message}`;
this._setStatus(`Build failed: ${status.message}`, true);
} else {
this._refreshStatus();
}