Require revocable authorization for automatic lobby removal
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { assertScalingOwnership } from '../autoscaling/ownership.js';
|
||||
import { removalAuthorization } from '../autoscaling/authorization.js';
|
||||
import { scalingIntent } from '../autoscaling/admission.js';
|
||||
import { putFileBlob, getFileBlob, blobSize } from '../db/file-blobs.js';
|
||||
import { concurrencyBlocker, preparingJobs } from './concurrency.js';
|
||||
import { isIP } from 'node:net';
|
||||
@@ -18,7 +20,7 @@ import { prepareNativeLaunch, evaluateNativePlacement, type PreparedNativeLaunch
|
||||
import { getServerKey, saveServerKey } from '../fleet/server-keys.js';
|
||||
import { activeBetaRemovalBlocker, getServer } from '../fleet/servers.js';
|
||||
import { nextLobbyNumber, type CreateServerInput, type CreateServerResult } from './instances.js';
|
||||
import { beginDeployment, deploymentStage, finishDeployment, REMOVING_SERVER } from './history.js';
|
||||
import { beginDeployment, deploymentStage, finishDeployment, REMOVING_SERVER, cancelRemoval } from './history.js';
|
||||
import { recordProgress, type CheckInput } from './progress.js';
|
||||
import { trackActivity } from '../pipeline/activity.js';
|
||||
import { fleetSettings } from '../settings.js';
|
||||
@@ -659,7 +661,11 @@ async function processJob(job: Job, eligibility: (job: Job) => string | null) {
|
||||
JOIN watchdog_incidents i ON i.id=s.source_id JOIN server_deployments d ON d.id=s.operation_id
|
||||
WHERE s.operation_id=? AND s.kind='watchdog' AND i.kind='health' AND d.triggered_by LIKE 'watchdog:%'`).get(job.id);
|
||||
if (recoveredWatchdog && occupancy.players !== null) { resolveRecoveredHealthOperation(job.id, occupancy.players, occupancy.source); return false; }
|
||||
if (occupancy.players !== 0) { hold(job, occupancy.players !== null ? `Waiting for ${occupancy.players} player(s) to leave.` : 'Waiting for a fresh local player count.'); return false; }
|
||||
if (occupancy.players !== 0) {
|
||||
if (job.action === 'destroy' && scalingIntent(job.id)) cancelRemoval(job.id, false);
|
||||
else hold(job, occupancy.players !== null ? `Waiting for ${occupancy.players} player(s) to leave.` : 'Waiting for a fresh local player count.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -729,6 +735,13 @@ async function processJob(job: Job, eligibility: (job: Job) => string | null) {
|
||||
? 'Host eligibility checked; player safety checks bypassed by admin override' : 'Host eligibility and safety checks passed' } });
|
||||
const payload: Record<string, unknown> = files.length ? { stageId: job.id } : {};
|
||||
if (overrideSafety) payload.safetyOverride = true;
|
||||
if (job.action === 'destroy') {
|
||||
const authorization = removalAuthorization(job.id, instance!.host_id);
|
||||
if (authorization) {
|
||||
if (overrideSafety) throw new Error('Autoscaling never bypasses player safety.');
|
||||
payload.autoscaling = authorization;
|
||||
}
|
||||
}
|
||||
if (prepared) {
|
||||
deploymentStage(job.id, 'Preparing launch files for the host agent', { phase: 'prepare', recipeStatus: 'attempted',
|
||||
checkpoint: { key: 'startup-queue', label: 'Startup capacity available' } });
|
||||
|
||||
Reference in New Issue
Block a user