// ============================================================================= // DEE Action: ASA_Scenario1_CheckNextGenManagerHasCapacity // Scenario: 1 — Migrate to Another Automation Manager // Stage: Acceptance Gate (second gate, after ReadyDelay) // // Purpose: // Before migrating an Automation Controller Instance from mixing-manager-legacy // to mixing-manager-nextgen, verify that the target manager has sufficient // capacity to host an additional instance. If the manager is at capacity, // return false so the task stays at SkippedGateFailed and retries on the // next polling pass. // // Demo Notes: // - The capacity is defined as a MES configuration value (int) in /Cmf/Tutorials/AutomationScheduleAction/Scenario1/NumberOfAvailableSlots. // - For demo purposes, the capacity is decremented every time an instance is scheduled, simulating the reservation of a slot for that instance. In a real scenario, the DEE would likely just check the current number of instances running on the target manager against a predefined maximum capacity. // - To test the scenario, set the NumberOfAvailableSlots configuration value to 0 // // DEE Contract: // Input - Task : AutomationScheduledActionTask (current task context) // Output - Result : Boolean (true = capacity available, false = no capacity) // // Fail-closed: any exception or unexpected result must be treated as false. // ============================================================================= using Cmf.Foundation.BusinessOrchestration.Abstractions; using Cmf.Foundation.BusinessOrchestration.ConfigurationManagement.InputObjects; using Cmf.Foundation.Common.Abstractions; using Cmf.Foundation.Configuration.Abstractions; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace Cmf.Custom.Tutorials.AutomationScheduleAction.Actions { public class ASA_Scenario1_CheckNextGenManagerHasCapacity : DeeDevBase { public override bool DeeTestCondition(Dictionary Input) { //---Start DEE Condition Code--- return true; //---End DEE Condition Code--- } public override Dictionary DeeActionCode(Dictionary Input) { //---Start DEE Code--- UseReference("", "Cmf.Foundation.BusinessOrchestration.Abstractions"); UseReference("", "Cmf.Foundation.BusinessOrchestration.ConfigurationManagement"); UseReference("", "Cmf.Foundation.BusinessOrchestration.ConfigurationManagement.InputObjects"); //Lock to ensure that only one is reserving a slot a the time lock(this.GetType()) { IServiceProvider _svcProvider = Input["ServiceProvider"] as IServiceProvider; IEntityFactory _entFactory = _svcProvider.GetService(); const string configName = "NumberOfAvailableSlots"; const string configParentPath = "/Cmf/Tutorials/AutomationScheduleAction/Scenario1"; const string configFullPath = $"{configParentPath}/{configName}"; IConfig nrSlotsConfig = _entFactory.Create(); if (!nrSlotsConfig.TryLoad(configFullPath)) { nrSlotsConfig.Name = configName; nrSlotsConfig.ValueType = "System.Int32"; nrSlotsConfig.Value = 1; //Default to 1 slot if config doesn't exist (so that only a single instance can be scheduled until the config is set up properly) nrSlotsConfig.Create(configParentPath); } int nrSlots = nrSlotsConfig.GetConfigValue(); if(nrSlots > 0) { nrSlotsConfig.Value = nrSlots - 1; nrSlotsConfig.Save(); Input["Result"] = true; } else { Input["Result"] = false; } } //---End DEE Code--- return Input; } } }