Add automatic retry to stream logs (#23098)

This commit is contained in:
Wendelin 2024-12-02 21:30:51 +01:00 committed by GitHub
parent f4ef4c628a
commit c3942d244d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 80 additions and 29 deletions

View File

@ -226,6 +226,25 @@ export const fetchHassioLogsFollow = async (
signal signal
); );
export const fetchHassioLogsFollowSkip = async (
hass: HomeAssistant,
provider: string,
signal: AbortSignal,
cursor: string,
skipLines: number,
lines = 100,
boot = 0
) =>
hass.callApiRaw(
"GET",
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs${boot !== 0 ? `/boots/${boot}` : ""}/follow`,
undefined,
{
Range: `entries=${cursor}:${skipLines}:${lines}`,
},
signal
);
export const getHassioLogDownloadUrl = (provider: string) => export const getHassioLogDownloadUrl = (provider: string) =>
`/api/hassio/${ `/api/hassio/${
provider.includes("_") ? `addons/${provider}` : provider provider.includes("_") ? `addons/${provider}` : provider

View File

@ -50,6 +50,7 @@ import {
fetchHassioBoots, fetchHassioBoots,
fetchHassioLogs, fetchHassioLogs,
fetchHassioLogsFollow, fetchHassioLogsFollow,
fetchHassioLogsFollowSkip,
fetchHassioLogsLegacy, fetchHassioLogsLegacy,
getHassioLogDownloadLinesUrl, getHassioLogDownloadLinesUrl,
getHassioLogDownloadUrl, getHassioLogDownloadUrl,
@ -428,13 +429,21 @@ class ErrorLogCard extends LitElement {
} }
} }
private async _loadLogs(): Promise<void> { private async _loadLogs(retry = false): Promise<void> {
this._error = undefined; this._error = undefined;
this._loadingState = "loading"; this._loadingState = "loading";
this._numberOfLines = retry ? (this._numberOfLines ?? 0) : 0;
if (!retry) {
this._loadingPrevState = undefined; this._loadingPrevState = undefined;
this._firstCursor = undefined; this._firstCursor = undefined;
this._numberOfLines = 0;
this._ansiToHtmlElement?.clear(); this._ansiToHtmlElement?.clear();
}
const streamLogs =
this._streamSupported &&
isComponentLoaded(this.hass, "hassio") &&
this.provider;
try { try {
if (this._logStreamAborter) { if (this._logStreamAborter) {
@ -442,17 +451,14 @@ class ErrorLogCard extends LitElement {
this._logStreamAborter = undefined; this._logStreamAborter = undefined;
} }
if ( if (streamLogs) {
this._streamSupported &&
isComponentLoaded(this.hass, "hassio") &&
this.provider
) {
this._logStreamAborter = new AbortController(); this._logStreamAborter = new AbortController();
if (!retry) {
// check if there are any logs at all // check if there are any logs at all
const testResponse = await fetchHassioLogs( const testResponse = await fetchHassioLogs(
this.hass, this.hass,
this.provider, this.provider!,
`entries=:-1:`, `entries=:-1:`,
this._boot this._boot
); );
@ -460,14 +466,29 @@ class ErrorLogCard extends LitElement {
if (!testLogs.trim()) { if (!testLogs.trim()) {
this._loadingState = "empty"; this._loadingState = "empty";
} }
}
const response = await fetchHassioLogsFollow( let response: Response;
if (retry && this._firstCursor) {
response = await fetchHassioLogsFollowSkip(
this.hass, this.hass,
this.provider, this.provider!,
this._logStreamAborter.signal,
this._firstCursor,
this._numberOfLines,
NUMBER_OF_LINES,
this._boot
);
} else {
response = await fetchHassioLogsFollow(
this.hass,
this.provider!,
this._logStreamAborter.signal, this._logStreamAborter.signal,
NUMBER_OF_LINES, NUMBER_OF_LINES,
this._boot this._boot
); );
}
if (response.headers.has("X-First-Cursor")) { if (response.headers.has("X-First-Cursor")) {
this._firstCursor = response.headers.get("X-First-Cursor")!; this._firstCursor = response.headers.get("X-First-Cursor")!;
@ -524,7 +545,7 @@ class ErrorLogCard extends LitElement {
if (!this._downloadSupported) { if (!this._downloadSupported) {
const downloadUrl = getHassioLogDownloadLinesUrl( const downloadUrl = getHassioLogDownloadLinesUrl(
this.provider, this.provider!,
this._numberOfLines, this._numberOfLines,
this._boot this._boot
); );
@ -532,6 +553,9 @@ class ErrorLogCard extends LitElement {
this._logsFileLink = signedUrl.path; this._logsFileLink = signedUrl.path;
}); });
} }
// first chunk loads successfully, reset retry param
retry = false;
} }
} }
} else { } else {
@ -554,6 +578,13 @@ class ErrorLogCard extends LitElement {
if (err.name === "AbortError") { if (err.name === "AbortError") {
return; return;
} }
// The stream can fail if the connection is lost or firefox service worker intercept the connection
if (!retry && streamLogs) {
this._loadLogs(true);
return;
}
this._error = (this.localizeFunc || this.hass.localize)( this._error = (this.localizeFunc || this.hass.localize)(
"ui.panel.config.logs.failed_get_logs", "ui.panel.config.logs.failed_get_logs",
{ {
@ -590,9 +621,10 @@ class ErrorLogCard extends LitElement {
private _handleConnectionStatus = (ev: HASSDomEvent<ConnectionStatus>) => { private _handleConnectionStatus = (ev: HASSDomEvent<ConnectionStatus>) => {
if (ev.detail === "disconnected" && this._logStreamAborter) { if (ev.detail === "disconnected" && this._logStreamAborter) {
this._logStreamAborter.abort(); this._logStreamAborter.abort();
this._loadingState = "loading";
} }
if (ev.detail === "connected") { if (ev.detail === "connected") {
this._loadLogs(); this._loadLogs(true);
} }
}; };