Update Harbor client and gateway integration workflows
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user