public async Task ReconcileAsync()

in edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/Agent.cs [113:208]


        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.deploymentMetrics.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)
                        {
                            if (this.currentConfig.Version != deploymentConfigInfo.Version)
                            {
                                await this.UpdateCurrentConfig(deploymentConfigInfo);
                            }

                            this.status = DeploymentStatus.Success;
                        }
                        else
                        {
                            try
                            {
                                using (this.deploymentMetrics.ReportDeploymentTime())
                                {
                                    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();
            }
        }