Skip to content

Commit

Permalink
feat: experimental Rust runtime (#1924)
Browse files Browse the repository at this point in the history
This Rust runtime implementation needs a fair amount of work to be
stable.

Features:
- Verb service and client.
- Can answer verb call requests.
- Can call out to verbs in other runtimes and process responses.
- FTL can build and restart the runtime automatically.
- Generates schema protos for verbs and args/return types recursively.

Limitations:
- Very limited functionality: verbs only, no generics.
- No error handling (unwraps everywhere).
- No scaffolding generation.
- No external module code generation.
- Only struct types referenced by verb arguments and returns in the same
module will correctly work.
- Hardcoded paths to crate dependencies in Cargo.toml
  • Loading branch information
gak authored Jul 2, 2024
1 parent 5a3aca6 commit 128eb56
Show file tree
Hide file tree
Showing 30 changed files with 4,416 additions and 2 deletions.
2 changes: 1 addition & 1 deletion backend/controller/scaling/localscaling/local_scaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (l *LocalScaling) SetReplicas(ctx context.Context, replicas int, idleRunner
simpleName := fmt.Sprintf("runner%d", keySuffix)
if err := kong.ApplyDefaults(&config, kong.Vars{
"deploymentdir": filepath.Join(l.cacheDir, "ftl-runner", simpleName, "deployments"),
"language": "go,kotlin",
"language": "go,kotlin,rust",
}); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion backend/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type Config struct {
TemplateDir string `help:"Template directory to copy into each deployment, if any." type:"existingdir"`
DeploymentDir string `help:"Directory to store deployments in." default:"${deploymentdir}"`
DeploymentKeepHistory int `help:"Number of deployments to keep history for." default:"3"`
Language []string `short:"l" help:"Languages the runner supports." env:"FTL_LANGUAGE" default:"go,kotlin"`
Language []string `short:"l" help:"Languages the runner supports." env:"FTL_LANGUAGE" default:"go,kotlin,rust"`
HeartbeatPeriod time.Duration `help:"Minimum period between heartbeats." default:"3s"`
HeartbeatJitter time.Duration `help:"Jitter to add to heartbeat period." default:"2s"`
}
Expand Down
2 changes: 2 additions & 0 deletions buildengine/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ func buildModule(ctx context.Context, sch *schema.Schema, module Module, filesTr
err = buildGoModule(ctx, sch, module, filesTransaction)
case "kotlin":
err = buildKotlinModule(ctx, sch, module)
case "rust":
err = buildRustModule(ctx, sch, module)
default:
return fmt.Errorf("unknown language %q", module.Config.Language)
}
Expand Down
21 changes: 21 additions & 0 deletions buildengine/build_rust.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package buildengine

import (
"context"
"fmt"
"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/internal/exec"
"github.com/TBD54566975/ftl/internal/log"
)

func buildRustModule(ctx context.Context, _ *schema.Schema, module Module) error {
logger := log.FromContext(ctx)

logger.Debugf("Using build command '%s'", module.Config.Build)
err := exec.Command(ctx, log.Debug, module.Config.Dir+"/_ftl", "bash", "-c", module.Config.Build).RunBuffered(ctx)
if err != nil {
return fmt.Errorf("failed to build module %q: %w", module.Config.Module, err)
}

return nil
}
9 changes: 9 additions & 0 deletions buildengine/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func extractDependencies(module Module) ([]string, error) {
case "kotlin":
return extractKotlinFTLImports(module.Config.Module, module.Config.Dir)

case "rust":
return extractRustFTLImports(module.Config.Module, module.Config.Dir)

default:
return nil, fmt.Errorf("unsupported language: %s", module.Config.Language)
}
Expand Down Expand Up @@ -136,3 +139,9 @@ func extractKotlinFTLImports(self, dir string) ([]string, error) {
sort.Strings(modules)
return modules, nil
}

func extractRustFTLImports(self, dir string) ([]string, error) {
fmt.Fprintf(os.Stderr, "RUST TODO extractRustFTLImports\n")

return nil, nil
}
14 changes: 14 additions & 0 deletions common/moduleconfig/moduleconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ func setConfigDefaults(moduleDir string, config *ModuleConfig) error {
}
config.Watch = append(config.Watch, watches...)
}

case "rust":
if config.Build == "" {
config.Build = "cargo build"
}
if config.DeployDir == "" {
config.DeployDir = "_ftl/target/debug"
}
if len(config.Deploy) == 0 {
config.Deploy = []string{"main"}
}
if len(config.Watch) == 0 {
config.Watch = []string{"**/*.rs", "Cargo.toml", "Cargo.lock"}
}
}

// Do some validation.
Expand Down
Loading

0 comments on commit 128eb56

Please sign in to comment.