mirror of
https://github.com/spaytac/orbiter.git
synced 2026-01-21 23:44:41 +00:00
126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package autoscaler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/client"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type Provider interface {
|
|
Scale(string, int, bool) error
|
|
Name() string
|
|
}
|
|
|
|
type Autoscalers map[string]Autoscaler
|
|
|
|
type Autoscaler struct {
|
|
provider Provider
|
|
serviceId string
|
|
targetUp int
|
|
targetDown int
|
|
CoolDown int
|
|
}
|
|
|
|
func NewAutoscaler(p Provider, serviceId string, targetUp int, targetDown int, coolDown int) Autoscaler {
|
|
a := Autoscaler{
|
|
provider: p,
|
|
serviceId: serviceId,
|
|
targetUp: targetUp,
|
|
targetDown: targetDown,
|
|
CoolDown: coolDown,
|
|
}
|
|
return a
|
|
}
|
|
|
|
func canScale(serviceId string, coolDown time.Duration) (retval bool, err error) {
|
|
retval = false
|
|
err = nil
|
|
ctx := context.Background()
|
|
dockerClient, err := client.NewEnvClient()
|
|
if err != nil {
|
|
logrus.WithField("error", err).Debug("Problem communication with Docker")
|
|
return
|
|
}
|
|
|
|
services, err := dockerClient.ServiceList(ctx, types.ServiceListOptions{})
|
|
if err != nil {
|
|
logrus.WithField("error", err).Debug("Bad comunication with Docker.")
|
|
return
|
|
}
|
|
|
|
for _, service := range services {
|
|
if service.Spec.Name != serviceId {
|
|
continue
|
|
}
|
|
// now < updatedAt + coolDown ??
|
|
if time.Now().Before(service.Meta.UpdatedAt.Add(coolDown)) {
|
|
err = errors.New(fmt.Sprintf("Cooldown period for %f seconds", service.Meta.UpdatedAt.Add(coolDown).Sub(time.Now()).Seconds()))
|
|
break
|
|
} else {
|
|
retval = true
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (a *Autoscaler) ScaleUp() error {
|
|
logrus.WithFields(logrus.Fields{
|
|
"service": a.serviceId,
|
|
"direction": true,
|
|
}).Infof("Received a new request to scale up %s with %d task.", a.serviceId, a.targetUp)
|
|
|
|
if ok, err := canScale(a.serviceId, time.Duration(a.CoolDown)*time.Second); ok == false {
|
|
logrus.Warn("Cannot scale up during coolDown period!")
|
|
return err
|
|
}
|
|
|
|
err := a.provider.Scale(a.serviceId, a.targetUp, true)
|
|
if err != nil {
|
|
logrus.WithFields(logrus.Fields{
|
|
"service": a.serviceId,
|
|
"direction": true,
|
|
"error": err.Error(),
|
|
}).Warnf("We had some problems to scale up %s.", a.serviceId)
|
|
} else {
|
|
logrus.WithFields(logrus.Fields{
|
|
"service": a.serviceId,
|
|
"direction": true,
|
|
}).Infof("Service %s scaled up.", a.serviceId)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (a *Autoscaler) ScaleDown() error {
|
|
logrus.WithFields(logrus.Fields{
|
|
"service": a.serviceId,
|
|
"direction": false,
|
|
}).Infof("Received a new request to scale down %s with %d task.", a.serviceId, a.targetDown)
|
|
|
|
if ok, err := canScale(a.serviceId, time.Duration(a.CoolDown)*time.Second); ok == false {
|
|
logrus.Warn("Cannot scale down during coolDown period!")
|
|
return err
|
|
}
|
|
err := a.provider.Scale(a.serviceId, a.targetDown, false)
|
|
|
|
if err != nil {
|
|
logrus.WithFields(logrus.Fields{
|
|
"service": a.serviceId,
|
|
"direction": false,
|
|
"error": err.Error(),
|
|
}).Warnf("We had some problems to scale down %s.", a.serviceId)
|
|
} else {
|
|
logrus.WithFields(logrus.Fields{
|
|
"service": a.serviceId,
|
|
"direction": false,
|
|
}).Infof("Service %s scaled down.", a.serviceId)
|
|
}
|
|
return err
|
|
}
|