run runs newCfg and starts all its apps if start is true. If any errors happen, cleanup is performed if any modules were provisioned; apps that were started already will be stopped, so this function should not leak resources if an error is returned. However, if no error is returned and start == fals
(newCfg *Config, start bool)
| 417 | // will want to use Run instead, which also |
| 418 | // updates the config's raw state. |
| 419 | func run(newCfg *Config, start bool) (Context, error) { |
| 420 | ctx, err := provisionContext(newCfg, start) |
| 421 | if err != nil { |
| 422 | globalMetrics.configSuccess.Set(0) |
| 423 | return ctx, err |
| 424 | } |
| 425 | |
| 426 | if !start { |
| 427 | return ctx, nil |
| 428 | } |
| 429 | |
| 430 | defer func() { |
| 431 | // if newCfg fails to start completely, clean up the already provisioned modules |
| 432 | // partially copied from provisionContext |
| 433 | if err != nil { |
| 434 | globalMetrics.configSuccess.Set(0) |
| 435 | ctx.cfg.cancelFunc(fmt.Errorf("configuration start error: %w", err)) |
| 436 | |
| 437 | if currentCtx.cfg != nil { |
| 438 | certmagic.Default.Storage = currentCtx.cfg.storage |
| 439 | } |
| 440 | } |
| 441 | }() |
| 442 | |
| 443 | // Start |
| 444 | err = func() error { |
| 445 | started := make([]string, 0, len(ctx.cfg.apps)) |
| 446 | for name, a := range ctx.cfg.apps { |
| 447 | err := a.Start() |
| 448 | if err != nil { |
| 449 | // an app failed to start, so we need to stop |
| 450 | // all other apps that were already started |
| 451 | for _, otherAppName := range started { |
| 452 | err2 := ctx.cfg.apps[otherAppName].Stop() |
| 453 | if err2 != nil { |
| 454 | err = fmt.Errorf("%v; additionally, aborting app %s: %v", |
| 455 | err, otherAppName, err2) |
| 456 | } |
| 457 | } |
| 458 | return fmt.Errorf("%s app module: start: %v", name, err) |
| 459 | } |
| 460 | started = append(started, name) |
| 461 | } |
| 462 | return nil |
| 463 | }() |
| 464 | if err != nil { |
| 465 | return ctx, err |
| 466 | } |
| 467 | globalMetrics.configSuccess.Set(1) |
| 468 | globalMetrics.configSuccessTime.SetToCurrentTime() |
| 469 | |
| 470 | // TODO: This event is experimental and subject to change. |
| 471 | ctx.emitEvent("started", nil) |
| 472 | |
| 473 | // now that the user's config is running, finish setting up anything else, |
| 474 | // such as remote admin endpoint, config loader, etc. |
| 475 | err = finishSettingUp(ctx, ctx.cfg) |
| 476 | return ctx, err |
no test coverage detected