Skip to content

Commit

Permalink
strategy: update interface to accept and respond with evaluation.
Browse files Browse the repository at this point in the history
The strategy calculation within the autoscaler is one portion of
the policy evaluation pipeline. Internal discussion has concluded
that it is appropriate to pass the evaluation to the strategy and
have it populate the action.

The new ScalingEvaluation encompasses all required information
the autoscaler needs when performing an autoscaling evaluation of
a policy.
  • Loading branch information
jrasell committed Sep 9, 2020
1 parent 9193d52 commit cec7ca3
Show file tree
Hide file tree
Showing 9 changed files with 472 additions and 179 deletions.
2 changes: 1 addition & 1 deletion agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (a *Agent) runEvalHandler(ctx context.Context, evalCh chan *sdk.ScalingEval
return
case policyEval := <-evalCh:
w := policy.NewWorker(a.logger, a.pluginManager, a.policyManager)
go w.HandlePolicy(ctx, policyEval.Policy)
go w.HandlePolicy(ctx, policyEval)
}
}
}
Expand Down
43 changes: 21 additions & 22 deletions plugins/builtin/strategy/target-value/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,28 @@ func (s *StrategyPlugin) PluginInfo() (*base.PluginInfo, error) {
}

// Run satisfies the Run function on the strategy.Strategy interface.
func (s *StrategyPlugin) Run(req sdk.StrategyRunReq) (sdk.ScalingAction, error) {
resp := sdk.ScalingAction{}
func (s *StrategyPlugin) Run(eval *sdk.ScalingCheckEvaluation, count int64) (*sdk.ScalingCheckEvaluation, error) {

// Read and parse target value from req.Config.
t := req.Config[runConfigKeyTarget]
t := eval.Check.Strategy.Config[runConfigKeyTarget]
if t == "" {
return resp, fmt.Errorf("missing required field `target`")
return nil, fmt.Errorf("missing required field `target`")
}

target, err := strconv.ParseFloat(t, 64)
if err != nil {
return resp, fmt.Errorf("invalid value for `target`: %v (%T)", t, t)
return nil, fmt.Errorf("invalid value for `target`: %v (%T)", t, t)
}

// Read and parse threshold value from req.Config.
th := req.Config[runConfigKeyThreshold]
th := eval.Check.Strategy.Config[runConfigKeyThreshold]
if th == "" {
th = defaultThreshold
}

threshold, err := strconv.ParseFloat(th, 64)
if err != nil {
return resp, fmt.Errorf("invalid value for `threshold`: %v (%T)", th, th)
return nil, fmt.Errorf("invalid value for `threshold`: %v (%T)", th, th)
}

var factor float64
Expand All @@ -104,47 +103,47 @@ func (s *StrategyPlugin) Run(req sdk.StrategyRunReq) (sdk.ScalingAction, error)
// queue has greater than 0 items in it.
switch target {
case 0:
factor = req.Metric
factor = eval.Metric
default:
factor = req.Metric / target
factor = eval.Metric / target
}

// Identify the direction of scaling, if any.
resp.Direction = s.calculateDirection(req.Count, factor, threshold)
if resp.Direction == sdk.ScaleDirectionNone {
return resp, nil
eval.Action.Direction = s.calculateDirection(count, factor, threshold)
if eval.Action.Direction == sdk.ScaleDirectionNone {
return eval, nil
}

var newCount int64

// Handle cases were users wish to scale from 0. If the current count is 0,
// then just use the factor as the new count to target. Otherwise use our
// standard calculation.
switch req.Count {
switch count {
case 0:
newCount = int64(math.Ceil(factor))
default:
newCount = int64(math.Ceil(float64(req.Count) * factor))
newCount = int64(math.Ceil(float64(count) * factor))
}

// Log at trace level the details of the strategy calculation. This is
// helpful in ultra-debugging situations when there is a need to understand
// all the calculations made.
s.logger.Trace("calculated scaling strategy results",
"policy_id", req.PolicyID, "current_count", req.Count, "new_count", newCount,
"metric_value", req.Metric, "factor", factor, "direction", resp.Direction)
"check_name", eval.Check.Name, "current_count", count, "new_count", newCount,
"metric_value", eval.Metric, "factor", factor, "direction", eval.Action.Direction)

// If the calculated newCount is the same as the current count, we do not
// need to scale so return an empty response.
if newCount == req.Count {
resp.Direction = sdk.ScaleDirectionNone
return resp, nil
if newCount == count {
eval.Action.Direction = sdk.ScaleDirectionNone
return eval, nil
}

resp.Count = newCount
resp.Reason = fmt.Sprintf("scaling %s because factor is %f", resp.Direction, factor)
eval.Action.Count = newCount
eval.Action.Reason = fmt.Sprintf("scaling %s because factor is %f", eval.Action.Direction, factor)

return resp, nil
return eval, nil
}

// calculateDirection is used to calculate the direction of scaling that should
Expand Down
Loading

0 comments on commit cec7ca3

Please sign in to comment.