This is an automated email from the ASF dual-hosted git repository.

kiranchavala pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.20 by this push:
     new 215ef984993 Allow cleaning up of networks stuck in Implementing state 
(#12409)
215ef984993 is described below

commit 215ef984993509bbb068f52c24b446be708c8dba
Author: Pearl Dsilva <[email protected]>
AuthorDate: Wed Sep 9 00:53:26 2026 -0400

    Allow cleaning up of networks stuck in Implementing state (#12409)
    
    * Allow cleaning up of networks stuck in Implementing state
    
    * extract code
---
 .../framework/jobs/impl/AsyncJobManagerImpl.java   | 80 ++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git 
a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java
 
b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java
index b9c9b22d9ea..f9fdc075132 100644
--- 
a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java
+++ 
b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java
@@ -957,6 +957,9 @@ public class AsyncJobManagerImpl extends ManagerBase 
implements AsyncJobManager,
                     }
 
                     logger.trace("End cleanup expired async-jobs");
+
+                    cleanupNetworksStuckInImplementing();
+
                 } catch (Throwable e) {
                     logger.error("Unexpected exception when trying to execute 
queue item, ", e);
                 }
@@ -964,6 +967,15 @@ public class AsyncJobManagerImpl extends ManagerBase 
implements AsyncJobManager,
         };
     }
 
+    private void cleanupNetworksStuckInImplementing() {
+        // Cleanup orphaned networks stuck in Implementing state without async 
jobs
+        try {
+            cleanupOrphanedNetworks();
+        } catch (Throwable e) {
+            logger.error("Unexpected exception when trying to cleanup orphaned 
networks", e);
+        }
+    }
+
     @DB
     protected void expungeAsyncJob(final AsyncJobVO job) {
         Transaction.execute(new TransactionCallbackNoReturn() {
@@ -1272,6 +1284,74 @@ public class AsyncJobManagerImpl extends ManagerBase 
implements AsyncJobManager,
         }
     }
 
+    /**
+     * Cleanup networks that are stuck in Implementing state without 
associated async jobs.
+     * This only processes networks that have been stuck for longer than the 
job expiration threshold.
+     */
+    private void cleanupOrphanedNetworks() {
+        try {
+            SearchCriteria<NetworkVO> sc = networkDao.createSearchCriteria();
+            sc.addAnd("state", SearchCriteria.Op.EQ, 
Network.State.Implementing);
+            sc.addAnd("removed", SearchCriteria.Op.NULL);
+            List<NetworkVO> implementingNetworks = networkDao.search(sc, null);
+
+            if (implementingNetworks == null || 
implementingNetworks.isEmpty()) {
+                return;
+            }
+
+            logger.debug("Found {} networks in Implementing state, checking 
for orphaned networks", implementingNetworks.size());
+
+            final long expireMinutes = JobExpireMinutes.value();
+            final Date cutoffTime = new Date(System.currentTimeMillis() - 
(expireMinutes * 60 * 1000));
+
+            for (NetworkVO network : implementingNetworks) {
+                if (network.getCreated().after(cutoffTime)) {
+                    logger.trace("Network {} in Implementing state is only {} 
minutes old (threshold: {} minutes), skipping cleanup",
+                               network.getId(),
+                               (System.currentTimeMillis() - 
network.getCreated().getTime()) / 60000,
+                               expireMinutes);
+                    continue;
+                }
+
+                List<AsyncJobVO> jobs = 
_jobDao.findInstancePendingAsyncJobs("Network", network.getAccountId());
+                boolean hasActiveJob = false;
+                for (AsyncJobVO job : jobs) {
+                    if (job.getInstanceId() != null && 
job.getInstanceId().equals(network.getId())) {
+                        hasActiveJob = true;
+                        break;
+                    }
+                }
+
+                if (hasActiveJob) {
+                    logger.debug("Network {} in Implementing state has active 
async job, skipping cleanup", network.getId());
+                    continue;
+                }
+
+                logger.warn("Found orphaned network {} in Implementing state 
without async job. " +
+                           "Network created: {}, age: {} minutes, expiration 
threshold: {} minutes. Transitioning to Shutdown state.",
+                           network.getId(), network.getCreated(),
+                           (System.currentTimeMillis() - 
network.getCreated().getTime()) / 60000,
+                           expireMinutes);
+                updateNetworkState(network);
+
+            }
+        } catch (Exception e) {
+            logger.error("Error while cleaning up orphaned networks", e);
+        }
+    }
+
+    private void updateNetworkState(NetworkVO network) {
+        try {
+            networkOrchestrationService.stateTransitTo(network, 
Network.Event.OperationFailed);
+            logger.info("Successfully transitioned orphaned network {} to 
Shutdown state using state machine", network.getId());
+        } catch (final NoTransitionException e) {
+            logger.debug("State transition failed for orphaned network {}, 
forcing state update", network.getId());
+            network.setState(Network.State.Shutdown);
+            networkDao.update(network.getId(), network);
+            logger.info("Successfully forced orphaned network {} to Shutdown 
state", network.getId());
+        }
+    }
+
     @Override
     public void onManagementNodeJoined(List<? extends ManagementServerHost> 
nodeList, long selfNodeId) {
     }

Reply via email to