async Task <(ModuleSet current, Exception ex)> GetCurrentModuleSetAsync(CancellationToken token) { ModuleSet current = null; Exception ex = null; try { current = await this.environment.GetModulesAsync(token); } catch (Exception e) when(!e.IsFatal()) { ex = e; } return(current, ex); }
public async Task ReconcileAsync(CancellationToken token) { ModuleSet moduleSetToReport = null; using (await this.reconcileLock.LockAsync(token)) { try { Events.StartingReconcile(); (ModuleSet current, DeploymentConfigInfo deploymentConfigInfo, Exception exception) = await this.GetReconcileData(token); moduleSetToReport = current; if (exception != null) { ExceptionDispatchInfo.Capture(exception).Throw(); } DeploymentConfig deploymentConfig = deploymentConfigInfo.DeploymentConfig; if (deploymentConfig.Equals(DeploymentConfig.Empty)) { this.status = DeploymentStatus.Success; } else { ModuleSet desiredModuleSet = deploymentConfig.GetModuleSet(); _ = Task.Run(() => this.availabilityMetric.ComputeAvailability(desiredModuleSet, current)) .ContinueWith(t => Events.UnknownFailure(t.Exception), TaskContinuationOptions.OnlyOnFaulted) .ConfigureAwait(false); // TODO - Update this logic to create identities only when needed, in the Command factory, instead of creating all the identities // up front here. That will allow handling the case when only the state of the system has changed (say one module crashes), and // no new identities need to be created. This will simplify the logic to allow EdgeAgent to work when offline. // But that required ModuleSet.Diff to be updated to include modules updated by deployment, and modules updated by state change. IImmutableDictionary <string, IModuleIdentity> identities = await this.moduleIdentityLifecycleManager.GetModuleIdentitiesAsync(desiredModuleSet, current); Plan plan = await this.planner.PlanAsync(desiredModuleSet, current, deploymentConfig.Runtime, identities); if (plan.IsEmpty) { this.status = DeploymentStatus.Success; } else { try { bool result = await this.planRunner.ExecuteAsync(deploymentConfigInfo.Version, plan, token); await this.UpdateCurrentConfig(deploymentConfigInfo); if (result) { this.status = DeploymentStatus.Success; } } catch (Exception ex) when(!ex.IsFatal()) { Events.PlanExecutionFailed(ex); await this.UpdateCurrentConfig(deploymentConfigInfo); throw; } } } } catch (Exception ex) when(!ex.IsFatal()) { switch (ex) { case ConfigEmptyException _: this.status = new DeploymentStatus(DeploymentStatusCode.ConfigEmptyError, ex.Message); Events.EmptyConfig(ex); break; case InvalidSchemaVersionException _: this.status = new DeploymentStatus(DeploymentStatusCode.InvalidSchemaVersion, ex.Message); Events.InvalidSchemaVersion(ex); break; case ConfigFormatException _: this.status = new DeploymentStatus(DeploymentStatusCode.ConfigFormatError, ex.Message); Events.InvalidConfigFormat(ex); break; default: this.status = new DeploymentStatus(DeploymentStatusCode.Failed, ex.Message); Events.UnknownFailure(ex); break; } } await this.reporter.ReportAsync(token, moduleSetToReport, await this.environment.GetRuntimeInfoAsync(), this.currentConfig.Version, this.status); Events.FinishedReconcile(); } }
public async Task ReconcileAsync(CancellationToken token) { Option <DeploymentStatus> status = Option.None <DeploymentStatus>(); ModuleSet moduleSetToReport = null; using (await this.reconcileLock.LockAsync(token)) { try { (ModuleSet current, DeploymentConfigInfo deploymentConfigInfo, Exception exception) = await this.GetReconcileData(token); moduleSetToReport = current; if (exception != null) { throw exception; } DeploymentConfig deploymentConfig = deploymentConfigInfo.DeploymentConfig; if (deploymentConfig != DeploymentConfig.Empty) { ModuleSet desiredModuleSet = deploymentConfig.GetModuleSet(); IImmutableDictionary <string, IModuleIdentity> identities = await this.moduleIdentityLifecycleManager.GetModuleIdentitiesAsync(desiredModuleSet, current); Plan plan = await this.planner.PlanAsync(desiredModuleSet, current, deploymentConfig.Runtime, identities); if (!plan.IsEmpty) { try { bool result = await this.planRunner.ExecuteAsync(deploymentConfigInfo.Version, plan, token); await this.UpdateCurrentConfig(deploymentConfigInfo); if (result) { status = Option.Some(DeploymentStatus.Success); } } catch (Exception ex) when(!ex.IsFatal()) { Events.PlanExecutionFailed(ex); await this.UpdateCurrentConfig(deploymentConfigInfo); throw; } } } else { status = Option.Some(DeploymentStatus.Success); } } catch (Exception ex) when(!ex.IsFatal()) { switch (ex) { case ConfigEmptyException _: status = Option.Some(new DeploymentStatus(DeploymentStatusCode.ConfigEmptyError, ex.Message)); Events.EmptyConfig(ex); break; case InvalidSchemaVersionException _: status = Option.Some(new DeploymentStatus(DeploymentStatusCode.InvalidSchemaVersion, ex.Message)); Events.InvalidSchemaVersion(ex); break; case ConfigFormatException _: status = Option.Some(new DeploymentStatus(DeploymentStatusCode.ConfigFormatError, ex.Message)); Events.InvalidConfigFormat(ex); break; default: status = Option.Some(new DeploymentStatus(DeploymentStatusCode.Failed, ex.Message)); Events.UnknownFailure(ex); break; } } await this.reporter.ReportAsync(token, moduleSetToReport, await this.environment.GetRuntimeInfoAsync(), this.currentConfig.Version, status); } }