diff --git a/go.mod b/go.mod index 9e7ae0a15..13331ee20 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/temporalio/ui-server/v2 v2.31.2 go.temporal.io/api v1.43.0 go.temporal.io/sdk v1.31.0 - go.temporal.io/server v1.26.2-rc.0 + go.temporal.io/server v1.26.2 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index e88688caf..104acfd96 100644 --- a/go.sum +++ b/go.sum @@ -358,8 +358,8 @@ go.temporal.io/api v1.43.0 h1:lBhq+u5qFJqGMXwWsmg/i8qn1UA/3LCwVc88l2xUMHg= go.temporal.io/api v1.43.0/go.mod h1:1WwYUMo6lao8yl0371xWUm13paHExN5ATYT/B7QtFis= go.temporal.io/sdk v1.31.0 h1:CLYiP0R5Sdj0gq8LyYKDDz4ccGOdJPR8wNGJU0JGwj8= go.temporal.io/sdk v1.31.0/go.mod h1:8U8H7rF9u4Hyb4Ry9yiEls5716DHPNvVITPNkgWUwE8= -go.temporal.io/server v1.26.2-rc.0 h1:jsWR2UzhPQ+UgDfqNHT6h6ZjzGTcw72i9KNkSNS0jN8= -go.temporal.io/server v1.26.2-rc.0/go.mod h1:tgY+4z/PuIdqs6ouV1bT90RWSWfEioWkzmrNrLYLUrk= +go.temporal.io/server v1.26.2 h1:vDW11lxslYPlGDbQklWi/tqbkVZ2ExtRO1jNjvZmUUI= +go.temporal.io/server v1.26.2/go.mod h1:tgY+4z/PuIdqs6ouV1bT90RWSWfEioWkzmrNrLYLUrk= go.temporal.io/version v0.3.0 h1:dMrei9l9NyHt8nG6EB8vAwDLLTwx2SvRyucCSumAiig= go.temporal.io/version v0.3.0/go.mod h1:UA9S8/1LaKYae6TyD9NaPMJTZb911JcbqghI2CBSP78= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= diff --git a/temporalcli/commands.gen.go b/temporalcli/commands.gen.go index 478d11786..f6ff5a4b5 100644 --- a/temporalcli/commands.gen.go +++ b/temporalcli/commands.gen.go @@ -1867,7 +1867,7 @@ func NewTemporalServerStartDevCommand(cctx *CommandContext, parent *TemporalServ s.Command.Flags().StringVarP(&s.DbFilename, "db-filename", "f", "", "Path to file for persistent Temporal state store. By default, Workflow Executions are lost when the server process dies.") s.Command.Flags().StringArrayVarP(&s.Namespace, "namespace", "n", nil, "Namespaces to be created at launch. The \"default\" Namespace is always created automatically.") s.Command.Flags().IntVarP(&s.Port, "port", "p", 7233, "Port for the front-end gRPC Service.") - s.Command.Flags().IntVar(&s.HttpPort, "http-port", 0, "Port for the HTTP API service. Default is off.") + s.Command.Flags().IntVar(&s.HttpPort, "http-port", 0, "Port for the HTTP API service. Defaults to a random free port.") s.Command.Flags().IntVar(&s.MetricsPort, "metrics-port", 0, "Port for '/metrics'. Default is off.") s.Command.Flags().IntVar(&s.UiPort, "ui-port", 0, "Port for the Web UI. Default is '--port' value + 1000.") s.Command.Flags().BoolVar(&s.Headless, "headless", false, "Disable the Web UI.") diff --git a/temporalcli/commands.server.go b/temporalcli/commands.server.go index dc268aaa3..3edaef80f 100644 --- a/temporalcli/commands.server.go +++ b/temporalcli/commands.server.go @@ -59,8 +59,11 @@ func (t *TemporalServerStartDevCommand) run(cctx *CommandContext, args []string) if err := devserver.CheckPortFree(opts.FrontendIP, opts.FrontendPort); err != nil { return fmt.Errorf("can't set frontend port %d: %w", opts.FrontendPort, err) } - if err := devserver.CheckPortFree(opts.FrontendIP, opts.FrontendHTTPPort); err != nil { - return fmt.Errorf("can't set frontend HTTP port %d: %w", opts.FrontendHTTPPort, err) + + if opts.FrontendHTTPPort > 0 { + if err := devserver.CheckPortFree(opts.FrontendIP, opts.FrontendHTTPPort); err != nil { + return fmt.Errorf("can't set frontend HTTP port %d: %w", opts.FrontendHTTPPort, err) + } } // Setup UI if !t.Headless { @@ -152,6 +155,10 @@ func (t *TemporalServerStartDevCommand) run(cctx *CommandContext, args []string) cctx.Printer.Printlnf("CLI %v\n", VersionString()) cctx.Printer.Printlnf("%-8s %v:%v", "Server:", toFriendlyIp(opts.FrontendIP), opts.FrontendPort) + // Only print HTTP port if explicitly provided to avoid promoting the unstable HTTP API. + if opts.FrontendHTTPPort > 0 { + cctx.Printer.Printlnf("%-8s %v:%v", "HTTP:", toFriendlyIp(opts.FrontendIP), opts.FrontendHTTPPort) + } if !t.Headless { cctx.Printer.Printlnf("%-8s http://%v:%v%v", "UI:", toFriendlyIp(opts.UIIP), opts.UIPort, opts.PublicPath) } diff --git a/temporalcli/commands.server_test.go b/temporalcli/commands.server_test.go index 40ca89629..e1b4586d8 100644 --- a/temporalcli/commands.server_test.go +++ b/temporalcli/commands.server_test.go @@ -25,26 +25,29 @@ import ( func TestServer_StartDev_Simple(t *testing.T) { port := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) + httpPort := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) startDevServerAndRunSimpleTest( t, // TODO(cretz): Remove --headless when // https://github.com/temporalio/ui/issues/1773 fixed - []string{"server", "start-dev", "-p", port, "--headless"}, + []string{"server", "start-dev", "-p", port, "--http-port", httpPort, "--headless"}, "127.0.0.1:"+port, ) } func TestServer_StartDev_IPv4Unspecified(t *testing.T) { port := strconv.Itoa(devserver.MustGetFreePort("0.0.0.0")) + httpPort := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) startDevServerAndRunSimpleTest( t, - []string{"server", "start-dev", "--ip", "0.0.0.0", "-p", port, "--headless"}, + []string{"server", "start-dev", "--ip", "0.0.0.0", "-p", port, "--http-port", httpPort, "--headless"}, "0.0.0.0:"+port, ) } func TestServer_StartDev_SQLitePragma(t *testing.T) { port := strconv.Itoa(devserver.MustGetFreePort("0.0.0.0")) + httpPort := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) dbFilename := filepath.Join(os.TempDir(), "devserver-sqlite-pragma.sqlite") defer func() { _ = os.Remove(dbFilename) @@ -55,7 +58,9 @@ func TestServer_StartDev_SQLitePragma(t *testing.T) { t, []string{ "server", "start-dev", - "-p", port, "--headless", + "-p", port, + "--http-port", httpPort, + "--headless", "--db-filename", dbFilename, "--sqlite-pragma", "journal_mode=WAL", "--sqlite-pragma", "synchronous=NORMAL", @@ -76,12 +81,14 @@ func TestServer_StartDev_IPv6Unspecified(t *testing.T) { } port := strconv.Itoa(devserver.MustGetFreePort("::")) + httpPort := strconv.Itoa(devserver.MustGetFreePort("::")) startDevServerAndRunSimpleTest( t, []string{ "server", "start-dev", "--ip", "::", "--ui-ip", "::1", "-p", port, + "--http-port", httpPort, "--ui-port", strconv.Itoa(devserver.MustGetFreePort("::")), "--http-port", strconv.Itoa(devserver.MustGetFreePort("::")), "--metrics-port", strconv.Itoa(devserver.MustGetFreePort("::"))}, @@ -138,9 +145,10 @@ func TestServer_StartDev_ConcurrentStarts(t *testing.T) { // Start in background, then wait for client to be able to connect port := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) + httpPort := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) resCh := make(chan *CommandResult, 1) go func() { - resCh <- h.Execute("server", "start-dev", "-p", port, "--headless", "--log-level", "never") + resCh <- h.Execute("server", "start-dev", "-p", port, "--http-port", httpPort, "--headless", "--log-level", "never") }() // Try to connect for a bit while checking for error @@ -191,11 +199,13 @@ func TestServer_StartDev_WithSearchAttributes(t *testing.T) { // Start in background, then wait for client to be able to connect port := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) + httpPort := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) resCh := make(chan *CommandResult, 1) go func() { resCh <- h.Execute( "server", "start-dev", "-p", port, + "--http-port", httpPort, "--headless", "--search-attribute", "search-attr-1=Int", "--search-attribute", "search-attr-2=kEyWoRdLiSt", diff --git a/temporalcli/commands_test.go b/temporalcli/commands_test.go index 7158bc02d..28933e5ef 100644 --- a/temporalcli/commands_test.go +++ b/temporalcli/commands_test.go @@ -371,7 +371,6 @@ func StartDevServer(t *testing.T, options DevServerOptions) *DevServer { d.Options.DynamicConfigValues["frontend.workerVersioningWorkflowAPIs"] = true d.Options.DynamicConfigValues["worker.buildIdScavengerEnabled"] = true d.Options.DynamicConfigValues["frontend.enableUpdateWorkflowExecution"] = true - d.Options.DynamicConfigValues["system.enableNexus"] = true d.Options.DynamicConfigValues["frontend.MaxConcurrentBatchOperationPerNamespace"] = 1000 d.Options.DynamicConfigValues["frontend.namespaceRPS.visibility"] = 100 d.Options.DynamicConfigValues["system.clusterMetadataRefreshInterval"] = 100 * time.Millisecond diff --git a/temporalcli/commandsgen/commands.yml b/temporalcli/commandsgen/commands.yml index dbc436d71..06169fa91 100644 --- a/temporalcli/commandsgen/commands.yml +++ b/temporalcli/commandsgen/commands.yml @@ -1689,9 +1689,8 @@ commands: default: 7233 - name: http-port type: int - description: | - Port for the HTTP API service. - Default is off. + description: Port for the HTTP API service. Defaults to a random free port. + default: 0 - name: metrics-port type: int description: | @@ -3544,4 +3543,4 @@ option-sets: description: | An external Nexus Endpoint that receives forwarded Nexus requests. May be used as an alternative to `--target-namespace` and - `--target-task-queue`. \ No newline at end of file + `--target-task-queue`. diff --git a/temporalcli/devserver/server.go b/temporalcli/devserver/server.go index 8ea5db1c7..230107cfc 100644 --- a/temporalcli/devserver/server.go +++ b/temporalcli/devserver/server.go @@ -117,6 +117,10 @@ func Start(options StartOptions) (*Server, error) { return nil, fmt.Errorf("missing initial failover version") } + if options.FrontendHTTPPort == 0 { + options.FrontendHTTPPort = MustGetFreePort(options.FrontendIP) + } + // Build servers var ui *uiserver.Server if options.UIIP != "" { @@ -227,7 +231,6 @@ func (s *StartOptions) buildServerOptions() ([]temporal.ServerOption, error) { dynConf[dynamicconfig.HistoryCacheHostLevelMaxSize.Key()] = 8096 // Up default visibility RPS dynConf[dynamicconfig.FrontendMaxNamespaceVisibilityRPSPerInstance.Key()] = 100 - // This doesn't enable Nexus but it is required for Nexus to work and simplifies the experience. // NOTE that the URL scheme is fixed to HTTP since the dev server doesn't support TLS at the time of writing. dynConf[nexusoperations.CallbackURLTemplate.Key()] = fmt.Sprintf( "http://%s:%d/namespaces/{{.NamespaceName}}/nexus/callback", MaybeEscapeIPv6(s.FrontendIP), s.FrontendHTTPPort) @@ -359,9 +362,7 @@ func (s *StartOptions) buildServiceConfig(frontend bool) config.Service { if frontend { conf.RPC.GRPCPort = s.FrontendPort conf.RPC.BindOnIP = s.FrontendIP - if s.FrontendHTTPPort > 0 { - conf.RPC.HTTPPort = s.FrontendHTTPPort - } + conf.RPC.HTTPPort = s.FrontendHTTPPort } else { conf.RPC.GRPCPort = MustGetFreePort(s.FrontendIP) conf.RPC.BindOnIP = s.FrontendIP