bool AreAllDepsSatisfied( AppDef appDef ) { // pokud jsou vsechny aplikace na kterych ta nase zavisi spousteny bool allDepsSatisfied = true; if (appDef.Dependencies != null) { foreach (var depName in appDef.Dependencies) { AppIdTuple depId = AppIdTuple.fromString(depName, appDef.Id.MachineId); if (!_appsState.ContainsKey(depId)) { // throw exception "Unknown dependency" throw new UnknownDependencyException(depName); } var dep = _appsState[depId]; if (!dep.Initialized) { allDepsSatisfied = false; break; } } } return allDepsSatisfied; }
/// <summary> /// Builds the list of waves as the result of application interdependencies. /// /// The first wawe will contain apps that do not depend on any other app. /// The second wave will contain the apps that depend on those from the first wave. /// Etc. untill all apps are processed. /// </summary> List<AppWave> BuildLaunchWaves() { // seznam zbyvajicich aplikaci // seznam uz pouzitych aplikaci (ktere uz byly vlozeny do vln) // Prochazim seznam zbylych aplikaci a pro kazdou hledam, zda vsechny jeji zavislosti uz se nachazi // v seznamu pouzitych aplikaci. Pokud ano, zkopiruju aplikaci do aktualni vlny. Pro projiti // vsech aplikaci pak vezmu aplikace z aktulne vytvorene vlny, smazu je ze zbyvajicich a vlozim do pouzitych. List<PlanApp> remaining = (from t in _plan.Apps where !t.Def.Disabled select t).ToList(); // those not yet moved to any of the waves List<PlanApp> used = new(); // those already moved to some of waves // allow fast lookup of appdef by its name Dictionary<AppIdTuple, PlanApp> dictApps = new(); foreach (var app in remaining) { dictApps[app.Def.Id] = app; } var waves = new List<AppWave>(); // the resulting list of waves // For each of the remaining apps check whether all its dependencias were already moved to some of prevoiusly // built waves; if so, add the app to the current wave and move it from remaining to used. while (remaining.Count > 0) { List<PlanApp> currentWave = new(); // the wave currently being built foreach (var app in remaining) { var ad = app.Def; bool allDepsSatisfied = true; if (ad.Dependencies != null) { foreach (var depName in ad.Dependencies) { AppIdTuple depId = AppIdTuple.fromString(depName, ad.Id.MachineId); if( dictApps.TryGetValue( depId, out var dep ) ) // dependency found in the plan { if( !used.Contains(dep) ) // but not yet placed to any previous wave { allDepsSatisfied = false; // meaning it can't be satisfied and we shall NOT try to run it in this wave break; } } } } if (allDepsSatisfied) { currentWave.Add(app); } } if( currentWave.Count > 0 ) { // move apps that were added to the current wave from remaining to used foreach (var app in currentWave) { remaining.Remove(app); used.Add(app); } // add current wave to the resulting list of wawes waves.Add(new AppWave( currentWave ) ); } else { // circular dependency??? log.Warn($" {_plan.Name}: Can't build launch wave, perhaps circular dependency?"); break; } } for( int i=0; i < waves.Count; i++ ) { var w = waves[i]; log.Debug($"Launch wave #{i}: {string.Join(", ", from app in w.Apps select app.Def.Id)}"); } return waves; }