From 057cb1bb6fe809d140686f8a70bc804c065dbae6 Mon Sep 17 00:00:00 2001 From: E M <5089238+emizzle@users.noreply.github.com> Date: Thu, 4 Jun 2026 18:14:00 +1000 Subject: [PATCH] try without waiting for pods to be killed --- Framework/KubernetesWorkflow/K8sController.cs | 63 ++++--------------- 1 file changed, 11 insertions(+), 52 deletions(-) diff --git a/Framework/KubernetesWorkflow/K8sController.cs b/Framework/KubernetesWorkflow/K8sController.cs index 5b8694bd..f796103a 100644 --- a/Framework/KubernetesWorkflow/K8sController.cs +++ b/Framework/KubernetesWorkflow/K8sController.cs @@ -162,66 +162,25 @@ namespace KubernetesWorkflow } /// - /// Ensures all pods are stopped and all PVCs are deleted before the namespace - /// is removed. This guarantees the underlying GCE PDs are released by the time - /// the namespace deletion is issued. + /// Deletes all PVCs in the namespace before it is removed, ensuring the backing + /// GCE PDs are released. Must be called before the namespace deletion API call. /// private void PrepareNamespaceForDeletion(string ns) { - ForceDeleteAllPodsInNamespace(ns); - WaitUntilAllPodsInNamespaceAreGone(ns); DeleteAllPvcsInNamespace(ns); } - /// - /// Sends a SIGKILL (gracePeriodSeconds=0) delete request for every pod in the - /// namespace. Individual failures are logged and skipped so one stuck pod does - /// not prevent the rest from being force-deleted. - /// - private void ForceDeleteAllPodsInNamespace(string ns) - { - var pods = client.Run(c => c.ListNamespacedPod(ns)); - foreach (var pod in pods.Items) - { - try - { - client.Run(c => c.DeleteNamespacedPod(pod.Name(), ns, gracePeriodSeconds: 0)); - log.Debug($"Force-deleted pod '{pod.Name()}' in namespace '{ns}'."); - } - catch (k8s.Autorest.HttpOperationException ex) - { - log.Error($"Failed to force-delete pod '{pod.Name()}' in namespace '{ns}': {ex.Response.ReasonPhrase}"); - } - } - } - - /// - /// Polls until no pods remain in the namespace, or until the 2-minute timeout - /// expires. On timeout the error is logged and execution continues: PVC deletion - /// will still be attempted with the finalizer removed (see DeleteAllPvcsInNamespace). - /// - private void WaitUntilAllPodsInNamespaceAreGone(string ns) - { - try - { - Time.WaitUntil( - () => !client.Run(c => c.ListNamespacedPod(ns)).Items.Any(), - TimeSpan.FromMinutes(2), - TimeSpan.FromSeconds(5), - $"WaitUntilAllPodsInNamespaceAreGone:{ns}"); - } - catch (TimeoutException) - { - log.Error($"Timed out waiting for pods in namespace '{ns}' to stop. Proceeding with PVC deletion."); - } - } - /// /// Removes the kubernetes.io/pvc-protection finalizer from each PVC then deletes - /// it. The finalizer is always patched off unconditionally: it is a no-op when - /// already absent, and it ensures deletion succeeds even when pods are still - /// present after a force-delete timeout (which would otherwise leave the PVC - /// stuck in Terminating and the backing GCE disk allocated indefinitely). + /// it. The finalizer is patched off unconditionally — it is a no-op when already + /// absent, and it guarantees deletion succeeds even when pods still reference the + /// PVC (which would otherwise leave the PVC stuck in Terminating and the backing + /// GCE disk allocated indefinitely). + /// + /// Note: deleting individual pods owned by a Deployment does not prevent pod + /// recreation (the ReplicaSet controller replaces them immediately). The finalizer + /// patch is therefore the correct mechanism here; namespace deletion handles pod + /// cleanup via the Deployment cascade. /// private void DeleteAllPvcsInNamespace(string ns) {