@sailboat-computer/health-monitoring
Version:
Comprehensive health monitoring system for sailboat computer v3 with marine-specific health checks
628 lines (537 loc) • 12.2 kB
text/typescript
/**
* Recovery action types and interfaces for self-healing mechanisms
*/
import {
HealthStatus,
HealthStatusType,
OperationalContext,
OperationalContextType,
MarineSystemType,
MarineSystemTypeType,
MarineEnvironmentStatus,
HealthCheckResult
} from '../types';
/**
* Recovery action types
*/
export enum RecoveryActionType {
/**
* Restart a component or service
*/
RESTART = 'restart',
/**
* Switch to a backup system
*/
FAILOVER = 'failover',
/**
* Reset a component to default settings
*/
RESET = 'reset',
/**
* Recalibrate a sensor or component
*/
RECALIBRATE = 'recalibrate',
/**
* Adjust configuration parameters
*/
ADJUST_CONFIG = 'adjust_config',
/**
* Reduce load on a system
*/
REDUCE_LOAD = 'reduce_load',
/**
* Isolate a component from the system
*/
ISOLATE = 'isolate',
/**
* Notify crew for manual intervention
*/
NOTIFY = 'notify'
}
/**
* Recovery action priority
*/
export enum RecoveryPriority {
/**
* Low priority, can be delayed
*/
LOW = 'low',
/**
* Normal priority
*/
NORMAL = 'normal',
/**
* High priority, execute soon
*/
HIGH = 'high',
/**
* Critical priority, execute immediately
*/
CRITICAL = 'critical'
}
/**
* Recovery action status
*/
export enum RecoveryStatus {
/**
* Action is pending execution
*/
PENDING = 'pending',
/**
* Action is currently executing
*/
EXECUTING = 'executing',
/**
* Action completed successfully
*/
SUCCEEDED = 'succeeded',
/**
* Action failed
*/
FAILED = 'failed',
/**
* Action was cancelled
*/
CANCELLED = 'cancelled',
/**
* Action timed out
*/
TIMEOUT = 'timeout'
}
/**
* Recovery action configuration
*/
export interface RecoveryActionConfig {
/**
* Unique ID for this recovery action
*/
actionId: string;
/**
* Human-readable name
*/
name: string;
/**
* Type of recovery action
*/
type: RecoveryActionType;
/**
* System type this action applies to
*/
marineSystemType: MarineSystemTypeType;
/**
* Priority of this action
*/
priority: RecoveryPriority;
/**
* Maximum execution time in ms
*/
timeout: number;
/**
* Maximum number of retry attempts
*/
maxRetries: number;
/**
* Delay between retries in ms
*/
retryDelay: number;
/**
* Whether this action requires manual approval
*/
requiresApproval: boolean;
/**
* Whether this action can run in automated mode
*/
automatedExecution: boolean;
/**
* Marine-specific settings
*/
marineSettings: {
/**
* Operational contexts where this action is allowed
*/
allowedContexts: OperationalContextType[];
/**
* Whether this action is allowed in rough sea conditions
*/
allowInRoughSeas: boolean;
/**
* Whether this action is power-aware
*/
powerAware: boolean;
/**
* Whether this action affects vessel safety
*/
safetyImpact: boolean;
/**
* Estimated power consumption in watts
*/
powerConsumption: number;
};
/**
* Action-specific parameters
*/
parameters: Record<string, any>;
}
/**
* Recovery action result
*/
export interface RecoveryActionResult {
/**
* Action ID
*/
actionId: string;
/**
* Action name
*/
name: string;
/**
* Action type
*/
type: RecoveryActionType;
/**
* Execution status
*/
status: RecoveryStatus;
/**
* Result message
*/
message: string;
/**
* Start time
*/
startTime: Date;
/**
* End time
*/
endTime: Date;
/**
* Execution duration in ms
*/
duration: number;
/**
* Number of retry attempts
*/
retryCount: number;
/**
* Whether the action was successful
*/
success: boolean;
/**
* Error details if failed
*/
error?: string;
/**
* Action-specific result details
*/
details?: Record<string, any>;
/**
* Marine context during execution
*/
marineContext: {
operationalContext: OperationalContextType;
environmentalConditions?: Partial<MarineEnvironmentStatus> | undefined;
};
/**
* Health check that triggered this action
*/
triggeringCheck?: {
checkId: string;
status: HealthStatusType;
score: number;
} | undefined;
/**
* Health check result after recovery attempt
*/
resultingCheck?: {
checkId: string;
status: HealthStatusType;
score: number;
};
}
/**
* Recovery policy
*/
export interface RecoveryPolicy {
/**
* Policy ID
*/
policyId: string;
/**
* Human-readable name
*/
name: string;
/**
* Health check ID this policy applies to
*/
checkId: string;
/**
* Marine system type
*/
marineSystemType: MarineSystemTypeType;
/**
* Health status threshold to trigger recovery
*/
triggerStatus: HealthStatusType;
/**
* Health score threshold to trigger recovery
*/
triggerScore: number;
/**
* Number of consecutive failures before triggering
*/
consecutiveFailures: number;
/**
* Recovery actions to attempt, in order
*/
actions: string[];
/**
* Whether to stop after first successful action
*/
stopOnSuccess: boolean;
/**
* Whether this policy is enabled
*/
enabled: boolean;
/**
* Cooldown period between recovery attempts in ms
*/
cooldownPeriod: number;
/**
* Maximum number of recovery attempts in a time window
*/
maxAttempts: number;
/**
* Time window for max attempts in ms
*/
attemptWindow: number;
/**
* Marine-specific settings
*/
marineSettings: {
/**
* Operational contexts where this policy is active
*/
activeContexts: OperationalContextType[];
/**
* Whether to apply in rough sea conditions
*/
activeInRoughSeas: boolean;
/**
* Whether this policy is power-aware
*/
powerAware: boolean;
/**
* Whether this policy affects vessel safety
*/
safetyImpact: boolean;
};
}
/**
* Recovery event
*/
export interface RecoveryEvent {
/**
* Event ID
*/
eventId: string;
/**
* Timestamp
*/
timestamp: Date;
/**
* Event type
*/
eventType: 'recovery_started' | 'recovery_completed' | 'recovery_failed' | 'policy_triggered' | 'action_executed';
/**
* System ID
*/
systemId: string;
/**
* Check ID that triggered recovery
*/
checkId?: string;
/**
* Policy ID
*/
policyId?: string;
/**
* Action ID
*/
actionId?: string;
/**
* Event data
*/
data: {
message: string;
details?: Record<string, any> | undefined;
marineContext: {
operationalContext: OperationalContextType;
environmentalConditions?: Partial<MarineEnvironmentStatus> | undefined;
};
};
/**
* Recovery result
*/
result?: RecoveryActionResult;
}
/**
* Abstract base class for recovery actions
*/
export abstract class BaseRecoveryAction {
protected config: RecoveryActionConfig;
protected lastResult?: RecoveryActionResult;
protected retryCount = 0;
constructor(config: RecoveryActionConfig) {
this.config = config;
}
/**
* Execute the recovery action
*/
async execute(
triggeringCheck: HealthCheckResult,
operationalContext: OperationalContextType,
marineEnvironment?: MarineEnvironmentStatus
): Promise<RecoveryActionResult> {
const startTime = new Date();
try {
// Check if action is allowed in current context
if (!this.isAllowedInContext(operationalContext, marineEnvironment)) {
return this.createFailedResult(
startTime,
new Date(),
'Action not allowed in current operational context',
operationalContext,
marineEnvironment,
triggeringCheck
);
}
// Execute the actual recovery action
const result = await this.performRecovery(triggeringCheck, operationalContext, marineEnvironment);
const endTime = new Date();
if (result.success) {
this.retryCount = 0;
this.lastResult = result;
return {
...result,
startTime,
endTime,
duration: endTime.getTime() - startTime.getTime(),
retryCount: this.retryCount,
triggeringCheck: {
checkId: triggeringCheck.checkId,
status: triggeringCheck.status,
score: triggeringCheck.score
}
};
} else {
// Handle retry logic
if (this.retryCount < this.config.maxRetries) {
this.retryCount++;
await new Promise(resolve => setTimeout(resolve, this.config.retryDelay));
return this.execute(triggeringCheck, operationalContext, marineEnvironment);
} else {
// Max retries reached
const failedResult = this.createFailedResult(
startTime,
new Date(),
`Recovery action failed after ${this.retryCount} retries: ${result.message}`,
operationalContext,
marineEnvironment,
triggeringCheck
);
this.lastResult = failedResult;
return failedResult;
}
}
} catch (error) {
const failedResult = this.createFailedResult(
startTime,
new Date(),
`Recovery action error: ${(error as Error).message}`,
operationalContext,
marineEnvironment,
triggeringCheck
);
this.lastResult = failedResult;
return failedResult;
}
}
/**
* Get the last execution result
*/
getLastResult(): RecoveryActionResult | undefined {
return this.lastResult;
}
/**
* Get action configuration
*/
getConfig(): RecoveryActionConfig {
return { ...this.config };
}
/**
* Check if action is allowed in current context
*/
protected isAllowedInContext(
operationalContext: OperationalContextType,
marineEnvironment?: MarineEnvironmentStatus
): boolean {
// Check operational context
if (!this.config.marineSettings.allowedContexts.includes(operationalContext)) {
return false;
}
// Check sea conditions
if (marineEnvironment?.seaState === 'rough' || marineEnvironment?.seaState === 'very_rough') {
if (!this.config.marineSettings.allowInRoughSeas) {
return false;
}
}
// Check power status
if (this.config.marineSettings.powerAware && marineEnvironment?.powerStatus === 'critical') {
// Only allow safety-critical actions when power is critical
return this.config.marineSettings.safetyImpact;
}
return true;
}
/**
* Create a failed result
*/
protected createFailedResult(
startTime: Date,
endTime: Date,
message: string,
operationalContext: OperationalContextType,
marineEnvironment?: MarineEnvironmentStatus,
triggeringCheck?: HealthCheckResult
): RecoveryActionResult {
return {
actionId: this.config.actionId,
name: this.config.name,
type: this.config.type,
status: RecoveryStatus.FAILED,
message,
startTime,
endTime,
duration: endTime.getTime() - startTime.getTime(),
retryCount: this.retryCount,
success: false,
error: message,
marineContext: {
operationalContext,
environmentalConditions: marineEnvironment ? { ...marineEnvironment } : undefined
},
triggeringCheck: triggeringCheck ? {
checkId: triggeringCheck.checkId,
status: triggeringCheck.status,
score: triggeringCheck.score
} : undefined
};
}
/**
* Abstract method to perform the actual recovery action
*/
protected abstract performRecovery(
triggeringCheck: HealthCheckResult,
operationalContext: OperationalContextType,
marineEnvironment?: MarineEnvironmentStatus
): Promise<RecoveryActionResult>;
}