From 953b62ef6e9d9abdefa2876bc111a099394844fe Mon Sep 17 00:00:00 2001 From: robbond Date: Thu, 5 Mar 2026 18:02:32 +0000 Subject: [PATCH] feat(db): add instance health monitoring fields --- lib/types.ts | 30 +++++++ .../CL38_instance_health_monitoring.sql | 78 +++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 supabase/migrations/CL38_instance_health_monitoring.sql diff --git a/lib/types.ts b/lib/types.ts index db6e9ef..4e8dea6 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -89,6 +89,16 @@ export type Database = { next_auto_sync_at: string | null; auto_sync_lock_until: string | null; auto_sync_lock_token: string | null; + health_enabled: boolean; + health_status: "ok" | "degraded" | "down" | "unknown"; + health_last_checked_at: string | null; + health_last_ok_at: string | null; + health_last_error: string | null; + health_last_latency_ms: number | null; + health_check_frequency_minutes: number; + health_next_check_at: string | null; + health_lock_until: string | null; + health_lock_token: string | null; created_at: string; }; Insert: { @@ -113,6 +123,16 @@ export type Database = { next_auto_sync_at?: string | null; auto_sync_lock_until?: string | null; auto_sync_lock_token?: string | null; + health_enabled?: boolean; + health_status?: "ok" | "degraded" | "down" | "unknown"; + health_last_checked_at?: string | null; + health_last_ok_at?: string | null; + health_last_error?: string | null; + health_last_latency_ms?: number | null; + health_check_frequency_minutes?: number; + health_next_check_at?: string | null; + health_lock_until?: string | null; + health_lock_token?: string | null; created_at?: string; }; Update: { @@ -137,6 +157,16 @@ export type Database = { next_auto_sync_at?: string | null; auto_sync_lock_until?: string | null; auto_sync_lock_token?: string | null; + health_enabled?: boolean; + health_status?: "ok" | "degraded" | "down" | "unknown"; + health_last_checked_at?: string | null; + health_last_ok_at?: string | null; + health_last_error?: string | null; + health_last_latency_ms?: number | null; + health_check_frequency_minutes?: number; + health_next_check_at?: string | null; + health_lock_until?: string | null; + health_lock_token?: string | null; created_at?: string; }; }; diff --git a/supabase/migrations/CL38_instance_health_monitoring.sql b/supabase/migrations/CL38_instance_health_monitoring.sql new file mode 100644 index 0000000..cb4203a --- /dev/null +++ b/supabase/migrations/CL38_instance_health_monitoring.sql @@ -0,0 +1,78 @@ +-- CL8: instance health monitoring fields + lock helpers + +alter table public.plesk_instances + add column if not exists health_enabled boolean not null default true, + add column if not exists health_status text not null default 'unknown', + add column if not exists health_last_checked_at timestamptz, + add column if not exists health_last_ok_at timestamptz, + add column if not exists health_last_error text, + add column if not exists health_last_latency_ms integer, + add column if not exists health_check_frequency_minutes integer not null default 30, + add column if not exists health_next_check_at timestamptz, + add column if not exists health_lock_until timestamptz, + add column if not exists health_lock_token text; + +alter table public.plesk_instances + drop constraint if exists plesk_instances_health_status_check; + +alter table public.plesk_instances + add constraint plesk_instances_health_status_check + check (health_status in ('ok', 'degraded', 'down', 'unknown')); + +alter table public.plesk_instances + drop constraint if exists plesk_instances_health_check_frequency_minutes_check; + +alter table public.plesk_instances + add constraint plesk_instances_health_check_frequency_minutes_check + check (health_check_frequency_minutes between 5 and 10080); + +create index if not exists idx_plesk_instances_health_due + on public.plesk_instances (health_enabled, health_next_check_at); + +create or replace function public.acquire_instance_health_lock( + p_instance_id uuid, + p_lock_token text, + p_ttl_seconds integer default 300, + p_force boolean default false +) +returns boolean +language plpgsql +security definer +set search_path = public +as $$ +declare + v_acquired boolean := false; +begin + update public.plesk_instances + set + health_lock_until = now() + make_interval(secs => p_ttl_seconds), + health_lock_token = p_lock_token + where id = p_instance_id + and health_enabled = true + and ( + p_force = true + or health_next_check_at is null + or health_next_check_at <= now() + ) + and (health_lock_until is null or health_lock_until < now()); + + get diagnostics v_acquired = row_count; + return v_acquired; +end; +$$; + +create or replace function public.release_instance_health_lock( + p_instance_id uuid, + p_lock_token text +) +returns void +language sql +security definer +set search_path = public +as $$ + update public.plesk_instances + set health_lock_until = null, + health_lock_token = null + where id = p_instance_id + and health_lock_token = p_lock_token; +$$; \ No newline at end of file