From e12cd130680e30c7afdbf073e8413984f5ebac74 Mon Sep 17 00:00:00 2001 From: Sam Bukowski Date: Thu, 19 Dec 2024 11:31:15 -0700 Subject: [PATCH 1/3] add start order to tui config, add composer ready check --- modules/cli/cmd/devrunner/config/tui.go | 15 ++++++ modules/cli/cmd/devrunner/run.go | 67 ++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/modules/cli/cmd/devrunner/config/tui.go b/modules/cli/cmd/devrunner/config/tui.go index e765377..4b81f0c 100644 --- a/modules/cli/cmd/devrunner/config/tui.go +++ b/modules/cli/cmd/devrunner/config/tui.go @@ -28,6 +28,9 @@ type TUIConfig struct { // Generic services start minimized GenericStartsMinimized bool `mapstructure:"generic_starts_minimized" toml:"generic_starts_minimized"` + // Generic services start position relative to known services + GenericStartPosition string `mapstructure:"generic_start_position" toml:"generic_start_position"` + // Accessibility settings HighlightColor string `mapstructure:"highlight_color" toml:"highlight_color"` BorderColor string `mapstructure:"border_color" toml:"border_color"` @@ -46,6 +49,7 @@ func DefaultTUIConfig() TUIConfig { ComposerStartsMinimized: false, SequencerStartsMinimized: false, GenericStartsMinimized: true, + GenericStartPosition: "after", HighlightColor: DefaultHighlightColor, BorderColor: DefaultBorderColor, } @@ -63,6 +67,7 @@ func (c TUIConfig) String() string { output += fmt.Sprintf("ComposerStartsMinimized: %v, ", c.ComposerStartsMinimized) output += fmt.Sprintf("SequencerStartsMinimized: %v, ", c.SequencerStartsMinimized) output += fmt.Sprintf("GenericStartsMinimized: %v", c.GenericStartsMinimized) + output += fmt.Sprintf("GenericStartPosition: %v", c.GenericStartPosition) output += fmt.Sprintf("HighlightColor: %s, ", c.HighlightColor) output += fmt.Sprintf("BorderColor: %s", c.BorderColor) output += "}" @@ -85,6 +90,16 @@ func LoadTUIConfigOrPanic(path string) TUIConfig { panic(err) } + // validate the generic start position value + switch config.GenericStartPosition { + case "before", "after", "default": + // valid values; do nothing + default: + log.Warnf("Invalid value for generic_start_position: %q. Valid values are: 'before', 'after', 'default'", config.GenericStartPosition) + log.Warnf("Setting generic_start_position to 'default'") + config.GenericStartPosition = "default" + } + return config } diff --git a/modules/cli/cmd/devrunner/run.go b/modules/cli/cmd/devrunner/run.go index 9fd8990..9366e22 100644 --- a/modules/cli/cmd/devrunner/run.go +++ b/modules/cli/cmd/devrunner/run.go @@ -138,6 +138,14 @@ func runCmdHandler(c *cobra.Command, _ []string) { } seqRunner = processrunner.NewProcessRunner(ctx, seqOpts) case "composer": + compRCOpts := processrunner.ReadyCheckerOpts{ + CallBackName: "Sequencer gRPC server is OK", + Callback: getComposerOKCallback(environment), + RetryCount: 10, + RetryInterval: 100 * time.Millisecond, + HaltIfFailed: false, + } + compReadinessCheck := processrunner.NewReadyChecker(compRCOpts) composerPath := getFlagPath(c, "composer-path", "composer", service.LocalPath) log.Debugf("arguments for composer service: %v", service.Args) composerOpts := processrunner.NewProcessRunnerOpts{ @@ -145,7 +153,7 @@ func runCmdHandler(c *cobra.Command, _ []string) { BinPath: composerPath, Env: environment, Args: service.Args, - ReadyCheck: nil, + ReadyCheck: &compReadinessCheck, LogPath: filepath.Join(logsDir, appStartTime+"-astria-composer.log"), ExportLogs: exportLogs, StartMinimized: tuiConfig.ComposerStartsMinimized, @@ -215,8 +223,17 @@ func runCmdHandler(c *cobra.Command, _ []string) { } } - // set the order of the services to start - allRunners := append([]processrunner.ProcessRunner{seqRunner, cometRunner, compRunner, condRunner}, genericRunners...) + // set the start order of the services + var allRunners []processrunner.ProcessRunner + + switch tuiConfig.GenericStartPosition { + case "before": + allRunners = append(genericRunners, []processrunner.ProcessRunner{seqRunner, cometRunner, compRunner, condRunner}...) + case "after": + allRunners = append([]processrunner.ProcessRunner{seqRunner, cometRunner, compRunner, condRunner}, genericRunners...) + default: + allRunners = append([]processrunner.ProcessRunner{seqRunner, cometRunner, compRunner, condRunner}, genericRunners...) + } runners, err := startProcessInOrder(ctx, allRunners...) if err != nil { @@ -252,10 +269,10 @@ func getFlagPath(c *cobra.Command, flag string, serviceName string, defaultValue // is started by the sequencer is OK by making an HTTP request to the health // endpoint. Being able to connect to the gRPC server is a requirement for both // the Conductor and Composer services. -func getSequencerOKCallback(config []string) func() bool { +func getSequencerOKCallback(environment []string) func() bool { // get the sequencer gRPC address from the environment var seqGRPCAddr string - for _, envVar := range config { + for _, envVar := range environment { if strings.HasPrefix(envVar, "ASTRIA_SEQUENCER_GRPC_ADDR") { seqGRPCAddr = strings.Split(envVar, "=")[1] break @@ -289,10 +306,10 @@ func getSequencerOKCallback(config []string) func() bool { // is started by Cometbft is OK by making an HTTP request to the health // endpoint. Being able to connect to the rpc server is a requirement for both // the Conductor and Composer services. -func getCometbftOKCallback(config []string) func() bool { +func getCometbftOKCallback(environment []string) func() bool { // get the CometBFT rpc address from the environment var seqRPCAddr string - for _, envVar := range config { + for _, envVar := range environment { if strings.HasPrefix(envVar, "ASTRIA_CONDUCTOR_SEQUENCER_COMETBFT_URL") { seqRPCAddr = strings.Split(envVar, "=")[1] break @@ -321,6 +338,42 @@ func getCometbftOKCallback(config []string) func() bool { } } +// getComposerOKCallback builds an anonymous function for use in a ProcessRunner +// ReadyChecker callback. The anonymous function checks if the rpc server that +// is started by Composer is OK by making an HTTP request to the health +// endpoint to confirm that the service and its rpc server have started. +func getComposerOKCallback(environment []string) func() bool { + // get the CometBFT rpc address from the environment + var composerRPCAddr string + for _, envVar := range environment { + if strings.HasPrefix(envVar, "ASTRIA_COMPOSER_GRPC_ADDR") { + composerRPCAddr = strings.Split(envVar, "=")[1] + break + } + } + composerRPCHealthURL := composerRPCAddr + "/health" + + // return the anonymous callback function + return func() bool { + // make the HTTP request + composerResp, err := http.Get(composerRPCHealthURL) + if err != nil { + log.WithError(err).Debug("Startup callback check to CometBFT rpc /health did not succeed") + return false + } + defer composerResp.Body.Close() + + // check status code + if composerResp.StatusCode == 200 { + log.Debug("CometBFT rpc server started") + return true + } else { + log.Debugf("CometBFT rpc status code: %d", composerResp.StatusCode) + return false + } + } +} + // startProcessInOrder starts the ProcessRunners in order they are provided, and // returns an array of all successfully started services. It will skip any // ProcessRunners that are nil. It will return an error if any of the From 4bbf9f3f8c78180134cf009a268406a816ed1760 Mon Sep 17 00:00:00 2001 From: Sam Bukowski Date: Thu, 19 Dec 2024 12:25:53 -0700 Subject: [PATCH 2/3] update composer ready check --- modules/cli/cmd/devrunner/run.go | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/modules/cli/cmd/devrunner/run.go b/modules/cli/cmd/devrunner/run.go index 9366e22..8c5434b 100644 --- a/modules/cli/cmd/devrunner/run.go +++ b/modules/cli/cmd/devrunner/run.go @@ -3,6 +3,7 @@ package devrunner import ( "context" "fmt" + "net" "net/http" "path/filepath" "strings" @@ -343,7 +344,7 @@ func getCometbftOKCallback(environment []string) func() bool { // is started by Composer is OK by making an HTTP request to the health // endpoint to confirm that the service and its rpc server have started. func getComposerOKCallback(environment []string) func() bool { - // get the CometBFT rpc address from the environment + // get the Composer rpc address from the environment var composerRPCAddr string for _, envVar := range environment { if strings.HasPrefix(envVar, "ASTRIA_COMPOSER_GRPC_ADDR") { @@ -351,26 +352,26 @@ func getComposerOKCallback(environment []string) func() bool { break } } - composerRPCHealthURL := composerRPCAddr + "/health" + + // Split address into host and port + host, port, err := net.SplitHostPort(composerRPCAddr) + if err != nil { + log.WithError(err).Error("Failed to split address into host and port") + return func() bool { return false } + } // return the anonymous callback function return func() bool { - // make the HTTP request - composerResp, err := http.Get(composerRPCHealthURL) + // Try to establish TCP connection + conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), 5*time.Second) if err != nil { - log.WithError(err).Debug("Startup callback check to CometBFT rpc /health did not succeed") + log.WithError(err).Debug("Startup callback TCP connection to Composer failed") return false } - defer composerResp.Body.Close() + defer conn.Close() - // check status code - if composerResp.StatusCode == 200 { - log.Debug("CometBFT rpc server started") - return true - } else { - log.Debugf("CometBFT rpc status code: %d", composerResp.StatusCode) - return false - } + log.Debug("Successfully established TCP connection to Composer") + return true } } From 52f5e0bc08abc630256fe3b12404a69fcd874c74 Mon Sep 17 00:00:00 2001 From: Sam Bukowski Date: Thu, 2 Jan 2025 15:12:03 -0700 Subject: [PATCH 3/3] update composer rollups env var handling --- modules/cli/cmd/devrunner/config/networks.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/modules/cli/cmd/devrunner/config/networks.go b/modules/cli/cmd/devrunner/config/networks.go index e4bb362..da7c3cf 100644 --- a/modules/cli/cmd/devrunner/config/networks.go +++ b/modules/cli/cmd/devrunner/config/networks.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "path/filepath" - "regexp" "github.com/astriaorg/astria-cli-go/modules/cli/cmd" log "github.com/sirupsen/logrus" @@ -212,19 +211,11 @@ func CreateNetworksConfig(binPath, configPath, localSequencerChainId, localNativ // the default environment variables for the network configuration. It uses the // BaseConfig to properly update the ASTRIA_COMPOSER_ROLLUPS env var. func (n NetworkConfig) GetEndpointOverrides(bc BaseConfig) []string { - rollupEndpoint, exists := bc["astria_composer_rollups"] + rollups, exists := bc["astria_composer_rollups"] if !exists { log.Error("ASTRIA_COMPOSER_ROLLUPS not found in BaseConfig") panic(fmt.Errorf("ASTRIA_COMPOSER_ROLLUPS not found in BaseConfig")) } - // get the rollup ws endpoint - pattern := `ws{1,2}:\/\/.*:\d+` - re, err := regexp.Compile(pattern) - if err != nil { - log.Error("Error compiling regex") - panic(err) - } - match := re.FindString(rollupEndpoint) return []string{ "ASTRIA_CONDUCTOR_SEQUENCER_GRPC_URL=" + n.SequencerGRPC, @@ -233,6 +224,6 @@ func (n NetworkConfig) GetEndpointOverrides(bc BaseConfig) []string { "ASTRIA_COMPOSER_SEQUENCER_CHAIN_ID=" + n.SequencerChainId, "ASTRIA_COMPOSER_SEQUENCER_ABCI_ENDPOINT=" + n.SequencerRPC, "ASTRIA_COMPOSER_SEQUENCER_GRPC_ENDPOINT=" + n.SequencerGRPC, - "ASTRIA_COMPOSER_ROLLUPS=" + n.RollupName + "::" + match, + "ASTRIA_COMPOSER_ROLLUPS=" + rollups, } }