@@ -957,13 +957,25 @@ public void reallyRun() {
957957 }
958958
959959 logger .trace ("End cleanup expired async-jobs" );
960+
961+ cleanupNetworksStuckInImplementing ();
962+
960963 } catch (Throwable e ) {
961964 logger .error ("Unexpected exception when trying to execute queue item, " , e );
962965 }
963966 }
964967 };
965968 }
966969
970+ private void cleanupNetworksStuckInImplementing () {
971+ // Cleanup orphaned networks stuck in Implementing state without async jobs
972+ try {
973+ cleanupOrphanedNetworks ();
974+ } catch (Throwable e ) {
975+ logger .error ("Unexpected exception when trying to cleanup orphaned networks" , e );
976+ }
977+ }
978+
967979 @ DB
968980 protected void expungeAsyncJob (final AsyncJobVO job ) {
969981 Transaction .execute (new TransactionCallbackNoReturn () {
@@ -1272,6 +1284,74 @@ private void cleanupFailedSnapshotsCreatedWithDefaultStrategy(final long msid) {
12721284 }
12731285 }
12741286
1287+ /**
1288+ * Cleanup networks that are stuck in Implementing state without associated async jobs.
1289+ * This only processes networks that have been stuck for longer than the job expiration threshold.
1290+ */
1291+ private void cleanupOrphanedNetworks () {
1292+ try {
1293+ SearchCriteria <NetworkVO > sc = networkDao .createSearchCriteria ();
1294+ sc .addAnd ("state" , SearchCriteria .Op .EQ , Network .State .Implementing );
1295+ sc .addAnd ("removed" , SearchCriteria .Op .NULL );
1296+ List <NetworkVO > implementingNetworks = networkDao .search (sc , null );
1297+
1298+ if (implementingNetworks == null || implementingNetworks .isEmpty ()) {
1299+ return ;
1300+ }
1301+
1302+ logger .debug ("Found {} networks in Implementing state, checking for orphaned networks" , implementingNetworks .size ());
1303+
1304+ final long expireMinutes = JobExpireMinutes .value ();
1305+ final Date cutoffTime = new Date (System .currentTimeMillis () - (expireMinutes * 60 * 1000 ));
1306+
1307+ for (NetworkVO network : implementingNetworks ) {
1308+ if (network .getCreated ().after (cutoffTime )) {
1309+ logger .trace ("Network {} in Implementing state is only {} minutes old (threshold: {} minutes), skipping cleanup" ,
1310+ network .getId (),
1311+ (System .currentTimeMillis () - network .getCreated ().getTime ()) / 60000 ,
1312+ expireMinutes );
1313+ continue ;
1314+ }
1315+
1316+ List <AsyncJobVO > jobs = _jobDao .findInstancePendingAsyncJobs ("Network" , network .getAccountId ());
1317+ boolean hasActiveJob = false ;
1318+ for (AsyncJobVO job : jobs ) {
1319+ if (job .getInstanceId () != null && job .getInstanceId ().equals (network .getId ())) {
1320+ hasActiveJob = true ;
1321+ break ;
1322+ }
1323+ }
1324+
1325+ if (hasActiveJob ) {
1326+ logger .debug ("Network {} in Implementing state has active async job, skipping cleanup" , network .getId ());
1327+ continue ;
1328+ }
1329+
1330+ logger .warn ("Found orphaned network {} in Implementing state without async job. " +
1331+ "Network created: {}, age: {} minutes, expiration threshold: {} minutes. Transitioning to Shutdown state." ,
1332+ network .getId (), network .getCreated (),
1333+ (System .currentTimeMillis () - network .getCreated ().getTime ()) / 60000 ,
1334+ expireMinutes );
1335+ updateNetworkState (network );
1336+
1337+ }
1338+ } catch (Exception e ) {
1339+ logger .error ("Error while cleaning up orphaned networks" , e );
1340+ }
1341+ }
1342+
1343+ private void updateNetworkState (NetworkVO network ) {
1344+ try {
1345+ networkOrchestrationService .stateTransitTo (network , Network .Event .OperationFailed );
1346+ logger .info ("Successfully transitioned orphaned network {} to Shutdown state using state machine" , network .getId ());
1347+ } catch (final NoTransitionException e ) {
1348+ logger .debug ("State transition failed for orphaned network {}, forcing state update" , network .getId ());
1349+ network .setState (Network .State .Shutdown );
1350+ networkDao .update (network .getId (), network );
1351+ logger .info ("Successfully forced orphaned network {} to Shutdown state" , network .getId ());
1352+ }
1353+ }
1354+
12751355 @ Override
12761356 public void onManagementNodeJoined (List <? extends ManagementServerHost > nodeList , long selfNodeId ) {
12771357 }
0 commit comments