Revert to regular pull immediately on delta server failure (code 400s)

If the delta server responds immediately with HTTP 4xx upon requesting a delta image,
this means the server is not able to supply the resource, so fall back to a regular pull
immediately.

Change-type: patch
Signed-off-by: Christina Ying Wang <christina@balena.io>
This commit is contained in:
Christina Ying Wang 2025-01-06 14:21:27 -08:00
parent 5c94c61b0a
commit 1fc242200f
2 changed files with 13 additions and 5 deletions

View File

@ -12,6 +12,7 @@ import {
DeltaStillProcessingError, DeltaStillProcessingError,
ImageAuthenticationError, ImageAuthenticationError,
InvalidNetGatewayError, InvalidNetGatewayError,
DeltaServerError,
} from './errors'; } from './errors';
import * as request from './request'; import * as request from './request';
import type { EnvVarObject } from '../types'; import type { EnvVarObject } from '../types';
@ -113,11 +114,7 @@ export async function fetchDeltaWithProgress(
onProgress: ProgressCallback, onProgress: ProgressCallback,
serviceName: string, serviceName: string,
): Promise<string> { ): Promise<string> {
const deltaSourceId = const deltaSourceId = deltaOpts.deltaSourceId ?? deltaOpts.deltaSource;
deltaOpts.deltaSourceId != null
? deltaOpts.deltaSourceId
: deltaOpts.deltaSource;
const timeout = deltaOpts.deltaApplyTimeout; const timeout = deltaOpts.deltaApplyTimeout;
const logFn = (str: string) => const logFn = (str: string) =>
@ -210,6 +207,10 @@ export async function fetchDeltaWithProgress(
} }
break; break;
case 3: case 3:
// If 400s status code, throw a more specific error & revert immediately to a regular pull
if (res.statusCode >= 400 && res.statusCode < 500) {
throw new DeltaServerError(res.statusCode, res.statusMessage);
}
if (res.statusCode !== 200) { if (res.statusCode !== 200) {
throw new Error( throw new Error(
`Got ${res.statusCode} when requesting v3 delta from delta server.`, `Got ${res.statusCode} when requesting v3 delta from delta server.`,
@ -235,6 +236,11 @@ export async function fetchDeltaWithProgress(
if (e instanceof OutOfSyncError) { if (e instanceof OutOfSyncError) {
logFn('Falling back to regular pull due to delta out of sync error'); logFn('Falling back to regular pull due to delta out of sync error');
return await fetchImageWithProgress(imgDest, deltaOpts, onProgress); return await fetchImageWithProgress(imgDest, deltaOpts, onProgress);
} else if (e instanceof DeltaServerError) {
logFn(
`Falling back to regular pull due to delta server error (${e.statusCode})${e.statusMessage ? `: ${e.statusMessage}` : ''}`,
);
return await fetchImageWithProgress(imgDest, deltaOpts, onProgress);
} else { } else {
logFn(`Delta failed with ${e}`); logFn(`Delta failed with ${e}`);
throw e; throw e;

View File

@ -70,6 +70,8 @@ export class InvalidNetGatewayError extends TypedError {}
export class DeltaStillProcessingError extends TypedError {} export class DeltaStillProcessingError extends TypedError {}
export class DeltaServerError extends StatusError {}
export class UpdatesLockedError extends TypedError {} export class UpdatesLockedError extends TypedError {}
export function isHttpConflictError(err: { statusCode: number }): boolean { export function isHttpConflictError(err: { statusCode: number }): boolean {