Skip to content

Commit

Permalink
feat: ftl dev now using buildengine (#1028)
Browse files Browse the repository at this point in the history
Still a bit more to do here + some testing, but wanted to push up
progress.

```sh
ftl dev ../ftl-examples/online-boutique/backend/services examples/go --recreate

info: Starting FTL with 1 controller(s) and 0 runner(s)
info:controller0: Web console available at: http://localhost:8892
info:time: Building module
info:cart: Building module
info:ad: Building module
info:currency: Building module
info:time: Deploying module
info:ad: Deploying module
info:cart: Deploying module
info:currency: Deploying module
info:controller0: Deployed currency-f4a032646d
info:controller0: Deployed time-ca2556f75d
info:controller0: Deployed cart-c9a2f125f9
info:controller0: Deployed ad-54a5b61320
info:shipping: Building module
info:payment: Building module
info:echo: Building module
info:productcatalog: Building module
info:echo: Deploying module
info:shipping: Deploying module
info:payment: Deploying module
info:productcatalog: Deploying module
info:controller0: Deployed payment-1f2ad7da27
info:controller0: Deployed productcatalog-f281d20587
info:controller0: Deployed shipping-47764b1f31
info:controller0: Deployed echo-88d74d32f8
info:recommendation: Building module
info:checkout: Building module
info:recommendation: Deploying module
info:checkout: Deploying module
info:controller0: Deployed checkout-ed4e646ba2
info:controller0: Deployed recommendation-bc93fb4a09
info:time: Building module
info:time: Deploying module
```
  • Loading branch information
wesbillman authored Mar 7, 2024
1 parent dcd6aee commit db9acb4
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 279 deletions.
84 changes: 73 additions & 11 deletions buildengine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
type Engine struct {
client ftlv1connect.ControllerServiceClient
modules map[string]Module
dirs []string
controllerSchema *xsync.MapOf[string, *schema.Module]
cancel func()
}
Expand All @@ -39,6 +40,7 @@ func New(ctx context.Context, client ftlv1connect.ControllerServiceClient, dirs
ctx = rpc.ContextWithClient(ctx, client)
e := &Engine{
client: client,
dirs: dirs,
modules: map[string]Module{},
controllerSchema: xsync.NewMapOf[string, *schema.Module](),
}
Expand Down Expand Up @@ -149,25 +151,85 @@ func (e *Engine) Import(ctx context.Context, schema *schema.Module) {
e.controllerSchema.Store(schema.Name, schema)
}

// Build attempts to build the specified modules, or all local modules if none are provided.
func (e *Engine) Build(ctx context.Context, modules ...string) error {
return e.buildWithCallback(ctx, nil, modules...)
// Build attempts to build all local modules.
func (e *Engine) Build(ctx context.Context) error {
return e.buildWithCallback(ctx, nil)
}

// Deploy attempts to build and deploy the specified modules, or all local modules if none are provided.
func (e *Engine) Deploy(ctx context.Context, replicas int32, waitForDeployOnline bool, modules ...string) error {
if len(modules) == 0 {
modules = maps.Keys(e.modules)
// Deploy attempts to build and deploy all local modules.
func (e *Engine) Deploy(ctx context.Context, replicas int32, waitForDeployOnline bool) error {
return e.buildAndDeploy(ctx, replicas, waitForDeployOnline)
}

// Dev builds and deploys all local modules and watches for changes, redeploying as necessary.
func (e *Engine) Dev(ctx context.Context, period time.Duration) error {
logger := log.FromContext(ctx)

// Build and deploy all modules first.
err := e.buildWithCallback(ctx, func(ctx context.Context, module Module) error {
return Deploy(ctx, module, 1, true, e.client)
})
if err != nil {
logger.Errorf(err, "initial deploy failed")
}

expectedBuilds := make(map[string]struct{}, len(modules))
for _, name := range modules {
expectedBuilds[name] = struct{}{}
// Then watch for changes and redeploy.
events := make(chan WatchEvent, 128)
watch := Watch(ctx, period, e.dirs...)
defer watch.Close()
watch.Subscribe(events)

for {
select {
case <-ctx.Done():
return ctx.Err()
case event := <-events:
switch event := event.(type) {
case WatchEventModuleAdded:
if _, exists := e.modules[event.Module.Module]; !exists {
e.modules[event.Module.Module] = event.Module
err = e.buildAndDeploy(ctx, 1, true, event.Module.Module)
if err != nil {
logger.Errorf(err, "deploy %s failed", event.Module.Module)
}
}
case WatchEventModuleRemoved:
// TODO: should we kill the deployment here?
delete(e.modules, event.Module.Module)

case WatchEventModuleChanged:
mustBuild := map[string]bool{event.Module.Module: true}
for key, module := range e.modules {
for _, dep := range module.Dependencies {
if dep == event.Module.Module {
mustBuild[key] = true
}
}
}

var modules []string
for key := range mustBuild {
modules = append(modules, key)
}

e.modules[event.Module.Module] = event.Module
err = e.buildAndDeploy(ctx, 1, true, modules...)
if err != nil {
logger.Errorf(err, "deploy %s failed", event.Module.Module)
}
}
}
}
}

return e.buildWithCallback(ctx, func(ctx context.Context, module Module) error {
func (e *Engine) buildAndDeploy(ctx context.Context, replicas int32, waitForDeployOnline bool, modules ...string) error {
err := e.buildWithCallback(ctx, func(ctx context.Context, module Module) error {
return Deploy(ctx, module, replicas, waitForDeployOnline, e.client)
}, modules...)
if err != nil {
return err
}
return nil
}

type buildCallback func(ctx context.Context, module Module) error
Expand Down
2 changes: 1 addition & 1 deletion buildengine/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func Watch(ctx context.Context, period time.Duration, dirs ...string) *pubsub.To
if _, haveModule := moduleConfigsByDir[existingModule.Module.Module]; !haveModule {
logger.Debugf("module %s removed: %s", existingModule.Module.Module, existingModule.Module.Dir)
topic.Publish(WatchEventModuleRemoved{Module: existingModule.Module})
delete(existingModules, existingModule.Module.Module)
delete(existingModules, existingModule.Module.ModuleConfig.Dir)
}
}

Expand Down
Loading

0 comments on commit db9acb4

Please sign in to comment.