diff --git a/cmd/ftl/cmd_dev.go b/cmd/ftl/cmd_dev.go index 9a03a898ec..5189d61d76 100644 --- a/cmd/ftl/cmd_dev.go +++ b/cmd/ftl/cmd_dev.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "time" "golang.org/x/sync/errgroup" @@ -20,25 +21,28 @@ type devCmd struct { func (d *devCmd) Run(ctx context.Context) error { client := rpc.ClientFromContext[ftlv1connect.ControllerServiceClient](ctx) - engine, err := buildengine.New(ctx, client, d.Dirs...) - if err != nil { - return err - } g, ctx := errgroup.WithContext(ctx) if !d.NoServe { + if d.ServeCmd.isRunning(ctx, client) { + return errors.New("FTL is already running") + } g.Go(func() error { return d.ServeCmd.Run(ctx) }) } - err = d.ServeCmd.pollControllerOnine(ctx, client) + err := d.ServeCmd.pollControllerOnine(ctx, client) if err != nil { return err } g.Go(func() error { + engine, err := buildengine.New(ctx, client, d.Dirs...) + if err != nil { + return err + } return engine.Dev(ctx, d.Watch) }) diff --git a/cmd/ftl/cmd_serve.go b/cmd/ftl/cmd_serve.go index 817efa92ff..385795e402 100644 --- a/cmd/ftl/cmd_serve.go +++ b/cmd/ftl/cmd_serve.go @@ -48,6 +48,14 @@ func (s *serveCmd) Run(ctx context.Context) error { logger := log.FromContext(ctx) client := rpc.ClientFromContext[ftlv1connect.ControllerServiceClient](ctx) + if s.Stop { + return killBackgroundProcess(logger) + } + + if s.isRunning(ctx, client) { + return errors.New("FTL is already running") + } + if s.Background { if s.Stop { // allow usage of --background and --stop together to "restart" the background process @@ -65,10 +73,6 @@ func (s *serveCmd) Run(ctx context.Context) error { os.Exit(0) } - if s.Stop { - return killBackgroundProcess(logger) - } - logger.Infof("Starting FTL with %d controller(s) and %d runner(s)", s.Controllers, s.Runners) dsn, err := s.setupDB(ctx) @@ -177,16 +181,16 @@ func killBackgroundProcess(logger *log.Logger) error { return nil } + if err := os.Remove(pidFilePath); err != nil { + logger.Errorf(err, "Failed to remove pid file: %v", err) + } + if err := syscall.Kill(pid, syscall.SIGTERM); err != nil { if !errors.Is(err, syscall.ESRCH) { return err } } - if err := os.Remove(pidFilePath); err != nil { - logger.Errorf(err, "Failed to remove pid file: %v", err) - } - logger.Infof("`ftl serve` stopped (pid: %d)", pid) return nil } @@ -375,3 +379,8 @@ func (s *serveCmd) pollControllerOnine(ctx context.Context, client ftlv1connect. } } } + +func (s *serveCmd) isRunning(ctx context.Context, client ftlv1connect.ControllerServiceClient) bool { + _, err := client.Ping(ctx, connect.NewRequest(&ftlv1.PingRequest{})) + return err == nil +}