diff options
| author | Christine Dodrill <me@christine.website> | 2018-04-05 08:29:12 -0700 |
|---|---|---|
| committer | Christine Dodrill <me@christine.website> | 2018-04-05 08:29:51 -0700 |
| commit | 6c8aa76bc51772837ed85be07207d6bf54198fb4 (patch) | |
| tree | 0280469f96f0e96f633f40e581bbe5973d911f37 /cmd | |
| parent | 6842e940cfc0f9cd1d11b4ce485f1e465f010ee2 (diff) | |
| download | x-6c8aa76bc51772837ed85be07207d6bf54198fb4.tar.xz x-6c8aa76bc51772837ed85be07207d6bf54198fb4.zip | |
add first steps for ghettoscale
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/ghettoscale/main.go | 42 | ||||
| -rw-r--r-- | cmd/ghettoscale/redis.go | 27 | ||||
| -rw-r--r-- | cmd/ghettoscale/scale.go | 75 |
3 files changed, 144 insertions, 0 deletions
diff --git a/cmd/ghettoscale/main.go b/cmd/ghettoscale/main.go new file mode 100644 index 0000000..8ad78c6 --- /dev/null +++ b/cmd/ghettoscale/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "flag" + "net/url" + "os" + "time" + + "github.com/Xe/ln" + _ "github.com/joho/godotenv/autoload" +) + +var ( + every = flag.Duration("every", 10*time.Minute, "how often this binary is being run") + do = flag.Int("do", 1, "do this number of scale checks, staggered by -every") +) + +func main() { + flag.Parse() + ctx := context.Background() + ctx = ln.WithF(ctx, ln.F{"at": "main"}) + + pool, err := NewRedisPoolFromURL(os.Getenv("REDIS_URL")) + if err != nil { + ln.FatalErr(ctx, err) + } + _ = pool + + for _, a := range flag.Args() { + ln.Log(ctx, ln.F{"url": a}) + u, err := url.Parse(a) + if err != nil { + ln.FatalErr(ctx, err) + } + + err = Check(ctx, u) + if err != nil { + ln.FatalErr(ctx, err) + } + } +} diff --git a/cmd/ghettoscale/redis.go b/cmd/ghettoscale/redis.go new file mode 100644 index 0000000..94375c0 --- /dev/null +++ b/cmd/ghettoscale/redis.go @@ -0,0 +1,27 @@ +package main + +import ( + "time" + + "github.com/garyburd/redigo/redis" +) + +// NewRedisPoolFromURL returns a new *redigo/redis.Pool configured for th1e supplied url +// The url can include a password in the standard form and if so is used to AUTH against +// the redis server. +func NewRedisPoolFromURL(url string) (*redis.Pool, error) { + return &redis.Pool{ + MaxIdle: 3, + IdleTimeout: 240 * time.Second, + Dial: func() (redis.Conn, error) { + return redis.DialURL(url) + }, + TestOnBorrow: func(c redis.Conn, t time.Time) error { + if time.Since(t) < time.Minute { + return nil + } + _, err := c.Do("PING") + return err + }, + }, nil +} diff --git a/cmd/ghettoscale/scale.go b/cmd/ghettoscale/scale.go new file mode 100644 index 0000000..fa503f8 --- /dev/null +++ b/cmd/ghettoscale/scale.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "fmt" + "net/url" +) + +// State is the state of the ghetto autoscaler. +type State int + +/* +States that this can be in + + digraph G { + ok [label="OK"] + scaling_up [label="Scaling Up"] + scaling_down [label="Scaling Down"] + max_scale [label="Max Scale"] + + init -> ok [label="test passes"] + init -> scaling_up [label="test fails"] + ok -> scaling_up [label="test fails"] + scaling_up -> scaling_up [label="test fails"] + scaling_up -> max_scale [label="test fails"] + scaling_up -> ok [label="test passes"] + scaling_down -> ok [label="minimum\nscale"] + ok -> scaling_down [label="test has\npassed\nn times"] + scaling_down -> scaling_down [label="test passes"] + max_scale -> scaling_down [label="test passes"] + max_scale -> ok [label="test passes"] + } + +This is the overall state machine for the autoscaler. +*/ +const ( + Init State = iota + OK + ScalingUp + MaxScale + ScalingDown +) + +func Check(ctx context.Context, u *url.URL) error { + switch u.Scheme { + case "heroku": + return CheckHeroku(ctx, u) + } + + return fmt.Errorf("no such scheme for %s", u.Scheme) +} + +func CheckHeroku(ctx context.Context, u *url.URL) error { + // q := u.Query() + var err error + + // heroku://printerfacts/web?kind=lang&metric=g:go.routines_max&min=1&max=3&stagger=1&mode=threshold&threshold=500 + // appID := u.Host + // processType := u.Path[1:] + // kind := q.Get("kind") + // metric := q.Get("metric") + // min := q.Get("min") + // max := q.Get("max") + // stagger := q.Get("stagger") + // mode := q.Get("mode") + + // get redis connection + // check if app:process type is currently staggered in redis + // if so decrement stagger counter in redis and exit + // fetch metrics data from metrics-api + // fetch current number of dynos for this app id and process type + // fetch state of the + + return err +} |
