Skip to content

Commit

Permalink
fix: add a build.lock file to gate the buildengine (#1670)
Browse files Browse the repository at this point in the history
Fixes #1636
  • Loading branch information
safeer authored Jun 11, 2024
1 parent aaebb97 commit e711523
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 0 deletions.
37 changes: 37 additions & 0 deletions buildengine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import (
"crypto/sha256"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"

"connectrpc.com/connect"
"github.com/alecthomas/types/pubsub"
"github.com/gofrs/flock"
"github.com/jpillora/backoff"
"github.com/puzpuzpuz/xsync/v3"
"golang.org/x/exp/maps"
Expand Down Expand Up @@ -83,6 +85,13 @@ func WithListener(listener Listener) Option {
//
// "dirs" are directories to scan for local modules.
func New(ctx context.Context, client ftlv1connect.ControllerServiceClient, moduleDirs []string, externalDirs []string, options ...Option) (*Engine, error) {
logger := log.FromContext(ctx)
lock, err := acquireBuildLock()
if err != nil {
return nil, err
}
logger.Debugf("Acquired lock file at %s", lock.Path())

ctx = rpc.ContextWithClient(ctx, client)
e := &Engine{
client: client,
Expand All @@ -102,6 +111,14 @@ func New(ctx context.Context, client ftlv1connect.ControllerServiceClient, modul
ctx, cancel := context.WithCancel(ctx)
e.cancel = cancel

go func() {
<-ctx.Done()
err := lock.Unlock()
if err != nil {
logger.Errorf(err, "failed to unlock file at %s", lock.Path())
}
}()

projects, err := DiscoverProjects(ctx, moduleDirs, externalDirs)
if err != nil {
return nil, fmt.Errorf("could not find projects: %w", err)
Expand Down Expand Up @@ -167,6 +184,26 @@ func (e *Engine) Close() error {
return nil
}

func acquireBuildLock() (*flock.Flock, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, err
}
lockFile := filepath.Join(homeDir, ".ftl", "build.lock")
if err := os.MkdirAll(filepath.Dir(lockFile), 0750); err != nil {
return nil, err
}
lock := flock.New(lockFile)
locked, err := lock.TryLock()
if err != nil {
return nil, err
}
if !locked {
return nil, fmt.Errorf("failed to lock file at: %s", lockFile)
}
return lock, nil
}

// Graph returns the dependency graph for the given modules.
//
// If no modules are provided, the entire graph is returned. An error is returned if
Expand Down
10 changes: 10 additions & 0 deletions buildengine/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,13 @@ func TestEngine(t *testing.T) {
err = engine.Build(ctx)
assert.NoError(t, err)
}

func TestDissallowMultipleEngines(t *testing.T) {
ctx := log.ContextWithNewDefaultLogger(context.Background())
engine, err := buildengine.New(ctx, nil, []string{"testdata/projects/alpha"}, nil)
assert.NoError(t, err)
defer engine.Close()

_, err = buildengine.New(ctx, nil, []string{"testdata/projects/alpha"}, nil)
assert.Error(t, err)
}

0 comments on commit e711523

Please sign in to comment.