aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2018-04-05 08:29:12 -0700
committerChristine Dodrill <me@christine.website>2018-04-05 08:29:51 -0700
commit6c8aa76bc51772837ed85be07207d6bf54198fb4 (patch)
tree0280469f96f0e96f633f40e581bbe5973d911f37 /cmd
parent6842e940cfc0f9cd1d11b4ce485f1e465f010ee2 (diff)
downloadx-6c8aa76bc51772837ed85be07207d6bf54198fb4.tar.xz
x-6c8aa76bc51772837ed85be07207d6bf54198fb4.zip
add first steps for ghettoscale
Diffstat (limited to 'cmd')
-rw-r--r--cmd/ghettoscale/main.go42
-rw-r--r--cmd/ghettoscale/redis.go27
-rw-r--r--cmd/ghettoscale/scale.go75
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
+}