Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prevent scaling apps or racks into "stuck" situations #82

Merged
merged 1 commit into from Oct 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 7 additions & 8 deletions api/models/app.go
Expand Up @@ -74,10 +74,6 @@ func GetApp(name string) (*App, error) {

app := appFromStack(res.Stacks[0])

app.Outputs = stackOutputs(res.Stacks[0])
app.Parameters = stackParameters(res.Stacks[0])
app.Tags = stackTags(res.Stacks[0])

return app, nil
}

Expand Down Expand Up @@ -684,10 +680,13 @@ func (a *App) Resources() Resources {

func appFromStack(stack *cloudformation.Stack) *App {
return &App{
Balancer: stackOutputs(stack)["BalancerHost"],
Name: *stack.StackName,
Release: stackParameters(stack)["Release"],
Status: humanStatus(*stack.StackStatus),
Balancer: stackOutputs(stack)["BalancerHost"],
Name: *stack.StackName,
Release: stackParameters(stack)["Release"],
Status: humanStatus(*stack.StackStatus),
Outputs: stackOutputs(stack),
Parameters: stackParameters(stack),
Tags: stackTags(stack),
}
}

Expand Down
47 changes: 47 additions & 0 deletions api/models/formation.go
Expand Up @@ -75,6 +75,43 @@ func SetFormation(app, process, count, memory string) error {
return err
}

rel, err := a.LatestRelease()

if err != nil {
return err
}

m, err := LoadManifest(rel.Manifest)

if err != nil {
return err
}

me := m.Entry(process)

if me == nil {
return fmt.Errorf("no such process: %s", process)
}

system, err := GetSystem()

if err != nil {
return err
}

c, err := strconv.Atoi(count)

if err != nil {
return err
}

// if the app has external ports we can only have n-1 instances of it
// because elbs expect the process to be available at the same port on
// every instance and we need room for the rolling updates
if len(me.ExternalPorts()) > 0 && c >= system.Count {
return fmt.Errorf("rack has %d instances, can't scale processes beyond %d", system.Count, system.Count-1)
}

params := map[string]string{}

if count != "" {
Expand All @@ -87,3 +124,13 @@ func SetFormation(app, process, count, memory string) error {

return a.UpdateParams(params)
}

func (f Formation) Entry(name string) *FormationEntry {
for _, fe := range f {
if fe.Name == name {
return &fe
}
}

return nil
}
58 changes: 58 additions & 0 deletions api/models/system.go
Expand Up @@ -59,6 +59,22 @@ func (r *System) Save() error {
return err
}

mac, err := maxAppConcurrency()

if err != nil {
return err
}

// dont scale the rack below the max concurrency plus one
// see formation.go for more details
if r.Count < (mac + 1) {
return fmt.Errorf("max process concurrency is %d, can't scale rack below %d instances", mac, mac+1)
}

fmt.Printf("mac %+v\n", mac)

return fmt.Errorf("stop")

params := map[string]string{
"InstanceCount": strconv.Itoa(r.Count),
"InstanceType": r.Type,
Expand All @@ -69,3 +85,45 @@ func (r *System) Save() error {

return app.UpdateParamsAndTemplate(params, template)
}

func maxAppConcurrency() (int, error) {
apps, err := ListApps()

if err != nil {
return 0, err
}

max := 0

for _, app := range apps {
rel, err := app.LatestRelease()

if err != nil {
return 0, err
}

m, err := LoadManifest(rel.Manifest)

if err != nil {
return 0, err
}

f, err := ListFormation(app.Name)

if err != nil {
return 0, err
}

for _, me := range m {
if m.HasExternalPorts() {
entry := f.Entry(me.Name)

if entry != nil && entry.Count > max {
max = entry.Count
}
}
}
}

return max, nil
}