Files
run/cmd/run/main.go
T

128 lines
5.2 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"os/signal"
"browser.local/run/api"
"browser.local/run/config"
runruntime "browser.local/run/runtime"
"browser.local/run/spool"
)
func main() {
if handled, exitCode := runruntime.RunManagedProcessHelper(os.Args); handled {
os.Exit(exitCode)
}
cfg := config.Load()
configSource := "environment-or-build-defaults"
if cfg.Mode == "self-update-helper" {
log.Printf("RUN phase=self_update_helper status=starting manifestPresent=%t", os.Getenv("RUN_UPDATE_MANIFEST") != "")
if err := runruntime.ApplySelfUpdateManifest(os.Getenv("RUN_UPDATE_MANIFEST")); err != nil {
fmt.Fprintf(os.Stderr, "Run self-update helper failed: %v\n", err)
os.Exit(1)
}
log.Printf("RUN phase=self_update_helper status=complete")
return
}
if packageConfig, ok, err := config.LoadPackageConfigFromEnv(); err != nil {
fmt.Fprintf(os.Stderr, "invalid run package config: %v\n", err)
os.Exit(1)
} else if ok {
cfg = config.ApplyPackageConfig(cfg, packageConfig)
configSource = "RUN_PACKAGE_CONFIG"
} else if packageConfig, ok, err := config.LoadPackageConfigBesideExecutable(); err != nil {
fmt.Fprintf(os.Stderr, "invalid bundled run package config: %v\n", err)
os.Exit(1)
} else if ok {
cfg = config.ApplyPackageConfig(cfg, packageConfig)
configSource = "package-config-beside-executable"
}
logWorkerPhases := cfg.Mode == "worker"
if logWorkerPhases {
log.Printf("RUN phase=bootstrap status=starting pid=%d args=%d", os.Getpid(), len(os.Args))
log.Printf("RUN phase=config status=loaded source=%s mode=%s platform=%s endpoint=%s server=%s plugin=%s component=%s componentKey=%s version=%s", configSource, cfg.Mode, diagnosticPlatformAddress(cfg.PlatformURL), diagnosticValue(cfg.RunEndpointID), diagnosticValue(cfg.ServerInstanceID), diagnosticValue(cfg.PluginID), diagnosticValue(cfg.ComponentKind), diagnosticValue(cfg.ComponentKey), diagnosticValue(cfg.Version))
log.Printf("RUN phase=platform_client status=building platform=%s", diagnosticPlatformAddress(cfg.PlatformURL))
}
client, err := api.NewPlatformClient(cfg.PlatformURL)
if err != nil {
fmt.Fprintf(os.Stderr, "invalid platform URL: %v\n", err)
os.Exit(1)
}
if logWorkerPhases {
log.Printf("RUN phase=platform_client status=ready base=%s", client.BaseURL())
}
if cfg.Mode == "worker" {
log.Printf("RUN phase=startup status=worker platform=%s endpoint=%s server=%s plugin=%s workspace=%s artifactQueue=%s maxJobs=%d", diagnosticPlatformAddress(cfg.PlatformURL), diagnosticValue(cfg.RunEndpointID), diagnosticValue(cfg.ServerInstanceID), diagnosticValue(cfg.PluginID), diagnosticValue(cfg.WorkspaceRoot), diagnosticValue(cfg.SpoolRoot), cfg.MaxJobs)
log.Printf("RUN phase=workspace_seed status=materializing present=%t workspace=%s componentKey=%s", cfg.WorkspaceSeed != "", diagnosticValue(cfg.WorkspaceRoot), diagnosticValue(cfg.ComponentKey))
if err := runruntime.MaterializeWorkspaceSeed(cfg); err != nil {
fmt.Fprintf(os.Stderr, "initialize plugin workspace assets: %v\n", err)
os.Exit(1)
}
log.Printf("RUN phase=workspace_seed status=ready workspace=%s", diagnosticValue(cfg.WorkspaceRoot))
log.Printf("RUN phase=artifact_queue status=opening path=%s", diagnosticValue(cfg.SpoolRoot))
artifactQueue, err := spool.NewArtifactQueue(cfg.SpoolRoot)
if err != nil {
fmt.Fprintf(os.Stderr, "initialize artifact queue: %v\n", err)
os.Exit(1)
}
log.Printf("RUN phase=artifact_queue status=ready path=%s", diagnosticValue(cfg.SpoolRoot))
liveLogSink := runruntime.NewLiveLogSink(client)
defer liveLogSink.Close()
log.Printf("RUN phase=worker_init status=starting endpoint=%s", diagnosticValue(cfg.RunEndpointID))
worker, err := runruntime.NewWorker(
cfg,
client,
runruntime.WithProcessLogSink(liveLogSink),
runruntime.WithLifecycleArtifactHook(&runruntime.QueueArtifactHook{Queue: artifactQueue}),
)
if err != nil {
fmt.Fprintf(os.Stderr, "initialize worker: %v\n", err)
os.Exit(1)
}
log.Printf("RUN phase=worker_init status=ready endpoint=%s", diagnosticValue(cfg.RunEndpointID))
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
log.Printf("RUN phase=worker_loop status=entering endpoint=%s", diagnosticValue(cfg.RunEndpointID))
if err := worker.Run(ctx); err != nil && err != context.Canceled && err != runruntime.ErrSelfUpdateRestartRequested {
fmt.Fprintf(os.Stderr, "run worker stopped: %v\n", err)
os.Exit(1)
}
log.Printf("RUN phase=worker_loop status=stopped endpoint=%s", diagnosticValue(cfg.RunEndpointID))
return
}
summary := runruntime.SmokeSummary(cfg)
summary.PlatformURL = client.BaseURL()
if err := json.NewEncoder(os.Stdout).Encode(summary); err != nil {
fmt.Fprintf(os.Stderr, "encode smoke summary: %v\n", err)
os.Exit(1)
}
}
func diagnosticValue(value string) string {
if value == "" {
return "-"
}
return value
}
func diagnosticPlatformAddress(rawURL string) string {
parsed, err := url.Parse(rawURL)
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
return "invalid"
}
address := parsed.Scheme + "://" + parsed.Host
if path := parsed.EscapedPath(); path != "" && path != "/" {
address += path
}
return address
}