diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index 6bb3f62df..ac9279bb8 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -100,7 +100,15 @@ func Run(ctx context.Context, templateUrl string, fsys afero.Fs, options ...func if err := utils.WriteFile(utils.ProjectRefPath, []byte(flags.ProjectRef), fsys); err != nil { return err } - // 5. Push migrations + // 5. Wait for project healthy + policy.Reset() + if err := backoff.RetryNotify(func() error { + fmt.Fprintln(os.Stderr, "Checking project health...") + return checkProjectHealth(ctx) + }, policy, newErrorCallback()); err != nil { + return err + } + // 6. Push migrations config := flags.NewDbConfigWithPassword(flags.ProjectRef) if err := writeDotEnv(keys, config, fsys); err != nil { fmt.Fprintln(os.Stderr, "Failed to create .env file:", err) @@ -137,6 +145,27 @@ func suggestAppStart(cwd string) string { return suggestion } +func checkProjectHealth(ctx context.Context) error { + params := api.CheckServiceHealthParams{ + Services: []api.CheckServiceHealthParamsServices{ + api.CheckServiceHealthParamsServicesDb, + }, + } + resp, err := utils.GetSupabase().CheckServiceHealthWithResponse(ctx, flags.ProjectRef, ¶ms) + if err != nil { + return err + } + if resp.JSON200 == nil { + return errors.Errorf("Error status %d: %s", resp.StatusCode(), resp.Body) + } + for _, service := range *resp.JSON200 { + if !service.Healthy { + return errors.Errorf("Service not healthy: %s (%s)", service.Name, service.Status) + } + } + return nil +} + const maxRetries = 8 func newBackoffPolicy(ctx context.Context) backoff.BackOffContext {