import { db } from '../db/index.js'; import { planScaling } from './planner.js'; import { scalingSnapshot } from './snapshot.js'; import { liveScaling, type ScalingPolicy, type ScalingDecision } from '../../autoscaling.js'; import { deploymentStage } from '../provisioning/history.js'; export interface ScalingIntent { policy_id: string; revision: number; decision: string; operation_id: string } export function scalingIntent(operationId: string): ScalingIntent | undefined { return db().prepare('SELECT policy_id,revision,decision,operation_id FROM autoscaling_decisions WHERE operation_id=? AND resolved=0').get(operationId) as ScalingIntent | undefined; } /** Rechecked before placement, after asynchronous preparation, and before dispatch. */ export function scalingAdmission(operationId: string): string | null { const intent = scalingIntent(operationId); if (!intent) return null; const row = db().prepare('SELECT * FROM autoscaling_policies WHERE id=?').get(intent.policy_id) as { id: string; settings: string; mode: ScalingPolicy['mode']; revision: number; paused_reason: string | null; owns_map: number } | undefined; let reason: string | null = null; const paused = (db().prepare("SELECT value FROM settings WHERE key='autoscaling_paused'").get() as { value: string } | undefined)?.value === '1'; if (!row || !liveScaling(row.mode) || !row.owns_map || row.revision !== intent.revision || row.paused_reason || paused) reason = 'Autoscaling policy is paused or changed.'; else { const policy: ScalingPolicy = { ...JSON.parse(row.settings), id: row.id, mode: row.mode, revision: row.revision, nextActionAt: 0, pausedReason: null, updatedAt: '' }; const requested = JSON.parse(intent.decision) as ScalingDecision; if (requested.action === 'destroy' && row.mode !== 'create-destroy') return 'Automatic removal is disabled.'; const snapshot = scalingSnapshot(policy, Date.now(), operationId); if (requested.action === 'create') { snapshot.reservedNames = snapshot.reservedNames.filter(n => n !== requested.server); snapshot.blockers = snapshot.blockers.filter(b => b !== `Unresolved native instance ${requested.server}.`); } const current = planScaling(policy, snapshot, Date.now()); if (current.action !== requested.action || current.server !== requested.server) reason = `Autoscaling intent no longer eligible: ${current.reason}`; } if (reason) deploymentStage(operationId, reason, { blocker: { code: 'autoscaling', message: reason, automatic: true } }); return reason; }