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)
{