Skip to content

Commit

Permalink
feat: add postgres setup and migration to ftl serve
Browse files Browse the repository at this point in the history
  • Loading branch information
wesbillman committed Oct 24, 2023
1 parent 821be2c commit dc7e49e
Showing 1 changed file with 102 additions and 0 deletions.
102 changes: 102 additions & 0 deletions cmd/ftl/cmd_serve.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package main

import (
"bytes"
"context"
"encoding/binary"
"fmt"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/alecthomas/errors"
"github.com/alecthomas/kong"
"golang.org/x/sync/errgroup"

"github.com/TBD54566975/ftl/backend/common/exec"
"github.com/TBD54566975/ftl/backend/common/log"
"github.com/TBD54566975/ftl/backend/controller"
"github.com/TBD54566975/ftl/backend/runner"
Expand All @@ -24,8 +28,16 @@ type serveCmd struct {
Runners int `short:"r" help:"Number of runners to start." default:"10"`
}

const ftlDBName = "ftl-db"

func (s *serveCmd) Run(ctx context.Context) error {
logger := log.FromContext(ctx)

dsn, err := setupDB(ctx)
if err != nil {
return errors.WithStack(err)
}

logger.Infof("Starting %d controller(s) and %d runner(s)", s.Controllers, s.Runners)

wg, ctx := errgroup.WithContext(ctx)
Expand All @@ -38,6 +50,7 @@ func (s *serveCmd) Run(ctx context.Context) error {
controllerAddresses = append(controllerAddresses, nextBind)
config := controller.Config{
Bind: nextBind,
DSN: *dsn,
}
if err := kong.ApplyDefaults(&config); err != nil {
return errors.WithStack(err)
Expand Down Expand Up @@ -105,6 +118,66 @@ func (s *serveCmd) Run(ctx context.Context) error {
return nil
}

func setupDB(ctx context.Context) (*string, error) {
logger := log.FromContext(ctx)

dsn := fmt.Sprintf("postgres://postgres:secret@localhost:5433/%s?sslmode=disable", ftlDBName)

logger.Infof("Checking for FTL database")

nameFlag := fmt.Sprintf("name=^/%s$", ftlDBName)
output, err := exec.Capture(ctx, ".", "docker", "ps", "-a", "--filter", nameFlag, "--format", "{{.Names}}")
if err != nil {
logger.Errorf(err, "%s", output)
return nil, errors.WithStack(err)
}

recreate := false

if len(output) == 0 {
logger.Infof("Creating FTL database")

err = exec.Command(ctx, logger.GetLevel(), "./", "docker", "run",
"-d", // run detached so we can follow with other commands
"--name", ftlDBName,
"--user", "postgres",
"--restart", "always",
"-e", "POSTGRES_PASSWORD=secret",
"-p", "5433:5432",
"--health-cmd=pg_isready",
"--health-interval=1s",
"--health-timeout=60s",
"--health-retries=60",
"--health-start-period=80s",
"postgres:latest", "postgres",
).Run()

if err != nil {
return nil, errors.WithStack(err)
}

err = pollContainerHealth(ctx, ftlDBName, 10*time.Second)
if err != nil {
return nil, err
}

recreate = true
}

dsnFlag := fmt.Sprintf("--dsn=%s", dsn)
if recreate {
logger.Infof("Initializing FTL schema")
err = exec.Command(ctx, logger.GetLevel(), ".", "ftl-initdb", "--recreate", dsnFlag).Run()
} else {
err = exec.Command(ctx, logger.GetLevel(), ".", "ftl-initdb", dsnFlag).Run()
}
if err != nil {
return nil, errors.WithStack(err)
}

return &dsn, nil
}

func incrementPort(baseURL *url.URL) (*url.URL, error) {
newURL := *baseURL

Expand All @@ -116,3 +189,32 @@ func incrementPort(baseURL *url.URL) (*url.URL, error) {
newURL.Host = fmt.Sprintf("%s:%d", baseURL.Hostname(), newPort+1)
return &newURL, nil
}

func pollContainerHealth(ctx context.Context, containerName string, timeout time.Duration) error {
logger := log.FromContext(ctx)
logger.Infof("Waiting for %s to be healthy", containerName)

pollCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

for {
select {
case <-pollCtx.Done():
return errors.New("timed out waiting for container to be healthy")
case <-time.After(1 * time.Second):
default:
var out bytes.Buffer
cmd := exec.Command(pollCtx, logger.GetLevel(), ".", "docker", "inspect", "--format", "{{.State.Health.Status}}", containerName)
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return errors.WithStack(err)
}

status := strings.TrimSpace(out.String())
if status == "healthy" {
return nil
}
}
}
}

0 comments on commit dc7e49e

Please sign in to comment.