fix(deployments): advance queue after cancellations (#11330)

This commit is contained in:
Andras Bacsai authored and GitHub committed 2026-08-17 16:27:00 +02:00
1 parent 82fe61bfd0
commit 5152698757
7 files changed
+288 -27

No files matched your search

@@ -54,6 +54,14 @@ class CleanupPreviewDeployment
$server
);
if ($result['cancelled_deployments'] > 0) {
try {
next_after_cancel($server);
} catch (\Throwable $e) {
\Log::warning("Failed to advance deployment queue after cleaning up preview for application {$application->id}: {$e->getMessage()}");
}
}
// Step 2: Stop and remove all running PR containers
$result['killed_containers'] = $this->stopRunningContainers(
$application,
@@ -98,13 +106,13 @@ class CleanupPreviewDeployment
$deployment->update([
'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
]);
$cancelled++;
// Add cancellation log entry
$deployment->addLogEntry('Deployment cancelled: Pull request closed.', 'stderr');
// Try to kill helper container if it exists
$this->killHelperContainer($deployment->deployment_uuid, $server);
$cancelled++;
} catch (\Throwable $e) {
\Log::warning("Failed to cancel deployment {$deployment->id}: {$e->getMessage()}");
}
+45 -23
View File
@@ -238,57 +238,71 @@ class DeployController extends Controller
ApplicationDeploymentStatus::IN_PROGRESS->value,
];
if (! in_array($deployment->status, $cancellableStatuses)) {
if (! in_array($deployment->status, $cancellableStatuses, true)) {
return response()->json([
'message' => "Deployment cannot be cancelled. Current status: {$deployment->status}",
], 400);
}
// Perform the cancellation
$cancelled = false;
$deploymentServer = Server::whereTeamId($teamId)->find($deployment->server_id);
try {
$deployment_uuid = $deployment->deployment_uuid;
$kill_command = "docker rm -f {$deployment_uuid}";
$build_server_id = $deployment->build_server_id ?? $deployment->server_id;
// Mark deployment as cancelled
$deployment->update([
'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
]);
$updated = ApplicationDeploymentQueue::whereKey($deployment->getKey())
->whereIn('status', $cancellableStatuses)
->update(['status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value]);
if ($updated !== 1) {
$deployment->refresh();
return response()->json([
'message' => "Deployment cannot be cancelled. Current status: {$deployment->status}",
], 400);
}
$deployment->status = ApplicationDeploymentStatus::CANCELLED_BY_USER->value;
$cancelled = true;
// Get the server
$server = Server::whereTeamId($teamId)->find($build_server_id);
if ($server) {
// Add cancellation log entry
$deployment->addLogEntry('Deployment cancelled by user via API.', 'stderr');
try {
if ($server) {
// Add cancellation log entry
$deployment->addLogEntry('Deployment cancelled by user via API.', 'stderr');
// Check if container exists and kill it
$checkCommand = "docker ps -a --filter name={$deployment_uuid} --format '{{.Names}}'";
$containerExists = instant_remote_process([$checkCommand], $server);
// Check if container exists and kill it
$checkCommand = "docker ps -a --filter name={$deployment_uuid} --format '{{.Names}}'";
$containerExists = instant_remote_process([$checkCommand], $server);
if ($containerExists && str($containerExists)->trim()->isNotEmpty()) {
instant_remote_process([$kill_command], $server);
$deployment->addLogEntry('Deployment container stopped.');
} else {
$deployment->addLogEntry('Deployment container not yet started. Will be cancelled when job checks status.');
}
if ($containerExists && str($containerExists)->trim()->isNotEmpty()) {
instant_remote_process([$kill_command], $server);
$deployment->addLogEntry('Deployment container stopped.');
} else {
$deployment->addLogEntry('Deployment container not yet started. Will be cancelled when job checks status.');
}
// Kill running process if process ID exists
if ($deployment->current_process_id) {
try {
// Kill running process if process ID exists
if ($deployment->current_process_id) {
$processKillCommand = "kill -9 {$deployment->current_process_id}";
instant_remote_process([$processKillCommand], $server);
} catch (\Throwable $e) {
// Process might already be gone
}
}
} catch (\Throwable $e) {
\Log::warning("Failed to clean up cancelled deployment {$deployment->id}: {$e->getMessage()}");
}
auditLog('api.deployment.cancelled', [
'team_id' => $teamId,
'deployment_uuid' => $deployment->deployment_uuid,
'application_id' => $application?->id,
'application_uuid' => $application?->uuid,
'application_id' => $deployment->application_id,
'application_uuid' => $deployment->application?->uuid,
'server_id' => $deployment->server_id,
]);
@@ -301,6 +315,14 @@ class DeployController extends Controller
return response()->json([
'message' => 'Failed to cancel deployment: '.$e->getMessage(),
], 500);
} finally {
if ($cancelled) {
try {
next_after_cancel($deploymentServer);
} catch (\Throwable $e) {
\Log::warning("Failed to advance deployment queue after cancelling deployment {$deployment->id}: {$e->getMessage()}");
}
}
}
}
+11
View File
@@ -158,12 +158,15 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
])
->get();
$cancelledDeployments = 0;
foreach ($activeDeployments as $activeDeployment) {
try {
// Mark deployment as cancelled
$activeDeployment->update([
'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
]);
$cancelledDeployments++;
// Add cancellation log entry
$activeDeployment->addLogEntry('Deployment cancelled: Pull request closed.', 'stderr');
@@ -186,6 +189,14 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
}
}
if ($cancelledDeployments > 0) {
try {
next_after_cancel($server);
} catch (\Throwable $e) {
\Log::warning("Failed to advance deployment queue after deleting preview {$this->resource->id}: {$e->getMessage()}");
}
}
try {
if ($server->isSwarm()) {
$escapedStackName = escapeshellarg("{$application->uuid}-{$pull_request_id}");
+7
View File
@@ -104,6 +104,13 @@ class CancelDeployment extends Tool
'server_id' => $deployment->server_id,
]);
try {
$deploymentServer = Server::whereTeamId($teamId)->find($deployment->server_id);
next_after_cancel($deploymentServer);
} catch (\Throwable $e) {
\Log::warning("Failed to advance deployment queue after cancelling deployment {$deployment->id}: {$e->getMessage()}");
}
return $this->mcpSuccess($request, $this->respond([
'ok' => true,
'message' => 'Deployment cancelled successfully.',