public static ScaleAction ScalingLogic(
            [QueueTrigger("Metrics")] Metric metric,
            [Table("Scaling", "{ResourceName}", "{Name}")] ScalingStateEntity stateEntity,
            [Table("Scaling", "{ResourceName}", "{Name}")] out ScalingStateEntity newStateEntity,
            TraceWriter log)
        {
            // 1. Deserialize state
            var state = stateEntity?.SerializedState != null
                ? JsonConvert.DeserializeObject <ScalingState>(stateEntity.SerializedState)
                : new ScalingState();

            var history = state.History;

            log.Info($"Scaling logic: Received {metric.Name}, previous state is {string.Join(", ", history)}");

            // 2. Add current metric value, remove old values
            history.Add(metric.Value);
            history.RemoveAll(e => e.Time < metric.Value.Time.Subtract(period));

            // 3. Compare the aggregates to thresholds, produce scaling action if needed
            ScaleAction action = null;

            if (history.Count >= 5 &&
                DateTime.Now - state.LastScalingActionTime > cooldownPeriod)
            {
                var average = (int)history.Average(e => e.Value);
                var maximum = (int)history.Max(e => e.Value);
                if (average > thresholdUp)
                {
                    log.Info($"Scaling logic: Value {average} is too high, scaling {metric.ResourceName} up...");
                    state.LastScalingActionTime = DateTime.Now;
                    action = new ScaleAction(metric.ResourceName, ScaleActionType.Up);
                }
                else if (maximum < thresholdDown)
                {
                    log.Info($"Scaling logic: Value {maximum} is low, scaling {metric.ResourceName} down...");
                    state.LastScalingActionTime = DateTime.Now;
                    action = new ScaleAction(metric.ResourceName, ScaleActionType.Down);
                }
            }

            // 4. Serialize the state back and return the action
            newStateEntity = stateEntity != null ? stateEntity : new ScalingStateEntity {
                PartitionKey = metric.ResourceName, RowKey = metric.Name
            };
            newStateEntity.SerializedState = JsonConvert.SerializeObject(state);
            return(action);
        }
        public static void Scaler([QueueTrigger("Actions")] ScaleAction action, TraceWriter log)
        {
            log.Info($"Scaler executed at: {DateTime.Now}");

            var secrets     = Environment.GetEnvironmentVariable("ServicePrincipal").Split(',');
            var credentials = SdkContext.AzureCredentialsFactory
                              .FromServicePrincipal(secrets[0], secrets[1], secrets[2], AzureEnvironment.AzureGlobalCloud);
            var azure = Azure.Configure()
                        .Authenticate(credentials)
                        .WithDefaultSubscription();

            var plan = azure.AppServices
                       .AppServicePlans
                       .List()
                       .First(p => p.Name.Contains(action.ResourceName));

            var newCapacity = action.Type == ScaleActionType.Down ? plan.Capacity - 1 : plan.Capacity + 1;

            log.Info($"Scaler: Switching {action.ResourceName} from {plan.Capacity} {action.Type} to {newCapacity}");

            plan.Update()
            .WithCapacity(newCapacity)
            .Apply();
        }