Update Harbor client and gateway integration workflows
Build and Deploy Gateway / build-and-push (push) Failing after 14s
Build and Deploy Gateway / deploy (push) Has been skipped

This commit is contained in:
2026-08-19 18:16:10 +03:00
parent 416b2b294a
commit daec12e013
63 changed files with 5016 additions and 108 deletions
+34 -1
View File
@@ -4,6 +4,10 @@ export type SyncErrorKind = 'incompatible-api' | 'control-unreachable' | 'fatal'
export interface HarborReducerState {
snapshot: HarborClientState | null;
failoverTransport: {
activeEpoch: string;
retiredEpochs: string[];
};
transport: {
bootStatus: 'loading' | 'ready' | SyncErrorKind;
lastSuccessfulSyncAt: string | null;
@@ -20,6 +24,7 @@ export type HarborAction =
export const initialHarborState: HarborReducerState = {
snapshot: null,
failoverTransport: { activeEpoch: '', retiredEpochs: [] },
transport: {
bootStatus: 'loading',
lastSuccessfulSyncAt: null,
@@ -31,6 +36,14 @@ export const initialHarborState: HarborReducerState = {
export const STALE_FAILURE_THRESHOLD = 3;
function failoverEpoch(snapshot: HarborClientState | null) {
return snapshot?.failover?.observationEpoch || '';
}
function failoverSequence(snapshot: HarborClientState | null) {
return snapshot?.failover?.observationSequence || 0;
}
export function classifySyncError(error: unknown): SyncErrorKind {
const candidate = error && typeof error === 'object' ? error as Record<string, unknown> : {};
const status = Number(candidate.status) || 0;
@@ -71,9 +84,29 @@ export function harborReducer(current: HarborReducerState, action: HarborAction)
const snapshot = action.snapshot;
const newer = !current.snapshot || snapshot.revision > current.snapshot.revision;
const equal = Boolean(current.snapshot) && snapshot.revision === current.snapshot?.revision;
const incomingEpoch = failoverEpoch(snapshot);
const activeEpoch = current.failoverTransport.activeEpoch || failoverEpoch(current.snapshot);
const unseenEpoch = Boolean(incomingEpoch)
&& incomingEpoch !== activeEpoch
&& !current.failoverTransport.retiredEpochs.includes(incomingEpoch);
const newerObservation = equal && Boolean(snapshot.failover) && (
unseenEpoch
|| (incomingEpoch === activeEpoch && failoverSequence(snapshot) > failoverSequence(current.snapshot))
);
const nextSnapshot = newer
? snapshot
: newerObservation && current.snapshot
? { ...current.snapshot, failover: snapshot.failover }
: current.snapshot;
const nextActiveEpoch = newer || unseenEpoch ? incomingEpoch : activeEpoch;
const retiredEpochs = unseenEpoch && activeEpoch
? [...current.failoverTransport.retiredEpochs, activeEpoch]
: current.failoverTransport.retiredEpochs;
return {
snapshot: newer ? snapshot : current.snapshot,
snapshot: nextSnapshot,
failoverTransport: { activeEpoch: nextActiveEpoch, retiredEpochs },
transport: {
bootStatus: 'ready',
lastSuccessfulSyncAt: action.receivedAt,
+2 -1
View File
@@ -1,6 +1,6 @@
export type OperationKey = 'connection' | 'serverApply' | 'profileAdd' | 'profileRename'
| 'profileSelect' | 'profileActivate' | 'profileRefresh' | 'profileDelete'
| 'gatewayAuto' | 'routeRules' | 'diagnosticsSettings';
| 'gatewayAuto' | 'routeRules' | 'diagnosticsSettings' | 'failover';
export interface OperationState {
status: 'running';
@@ -22,6 +22,7 @@ const OPERATION_KEYS: readonly OperationKey[] = [
'gatewayAuto',
'routeRules',
'diagnosticsSettings',
'failover',
];
// The backend has one canonical revision and one mutation queue, so the UI mirrors that lock.