From 1f715b60016c1b7654ce65bf4a43b79fa0459c7e Mon Sep 17 00:00:00 2001 From: Sai Asish Y Date: Thu, 21 May 2026 01:37:29 -0700 Subject: [PATCH 1/4] Add persistence info to start-dev banner Closes #634 --- internal/temporalcli/commands.server.go | 5 ++ internal/temporalcli/commands.server_test.go | 79 ++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/internal/temporalcli/commands.server.go b/internal/temporalcli/commands.server.go index 90c5b2fe3..2e9fe2676 100644 --- a/internal/temporalcli/commands.server.go +++ b/internal/temporalcli/commands.server.go @@ -169,6 +169,11 @@ func (t *TemporalServerStartDevCommand) run(cctx *CommandContext, args []string) cctx.Printer.Printlnf("%-17s http://%v:%v%v", "Temporal UI:", toFriendlyIp(opts.UIIP), opts.UIPort, opts.PublicPath) } cctx.Printer.Printlnf("%-17s http://%v:%v/metrics", "Temporal Metrics:", toFriendlyIp(opts.FrontendIP), opts.MetricsPort) + if t.DbFilename == "" { + cctx.Printer.Printlnf("%-17s %v", "Persistence:", "in-memory (Workflow Executions are lost when the server process exits)") + } else { + cctx.Printer.Printlnf("%-17s file (%v)", "Persistence:", t.DbFilename) + } <-cctx.Done() if !t.Parent.Parent.LogLevel.ChangedFromDefault { // The server routinely emits various warnings on shutdown. diff --git a/internal/temporalcli/commands.server_test.go b/internal/temporalcli/commands.server_test.go index 8c25558d9..9c111b72d 100644 --- a/internal/temporalcli/commands.server_test.go +++ b/internal/temporalcli/commands.server_test.go @@ -271,6 +271,85 @@ func TestServer_StartDev_WithSearchAttributes(t *testing.T) { } } +func TestServer_StartDev_BannerPersistenceInMemory(t *testing.T) { + h := NewCommandHarness(t) + defer h.Close() + + 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") + }() + + // Wait until the server is dial-able, then cancel + var cl client.Client + h.EventuallyWithT(func(t *assert.CollectT) { + select { + case res := <-resCh: + require.NoError(t, res.Err) + require.Fail(t, "got early server result") + default: + } + var err error + cl, err = client.Dial(client.Options{HostPort: "127.0.0.1:" + port}) + assert.NoError(t, err) + }, 3*time.Second, 200*time.Millisecond) + defer cl.Close() + + h.CancelContext() + var res *CommandResult + select { + case <-time.After(20 * time.Second): + h.Fail("didn't cleanup after 20 seconds") + case res = <-resCh: + h.NoError(res.Err) + } + out := res.Stdout.String() + h.Contains(out, "Persistence:") + h.Contains(out, "in-memory") +} + +func TestServer_StartDev_BannerPersistenceFile(t *testing.T) { + h := NewCommandHarness(t) + defer h.Close() + + port := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) + httpPort := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) + dbFilename := filepath.Join(t.TempDir(), "devserver-banner.sqlite") + resCh := make(chan *CommandResult, 1) + go func() { + resCh <- h.Execute("server", "start-dev", "-p", port, "--http-port", httpPort, + "--headless", "--db-filename", dbFilename) + }() + + var cl client.Client + h.EventuallyWithT(func(t *assert.CollectT) { + select { + case res := <-resCh: + require.NoError(t, res.Err) + require.Fail(t, "got early server result") + default: + } + var err error + cl, err = client.Dial(client.Options{HostPort: "127.0.0.1:" + port}) + assert.NoError(t, err) + }, 3*time.Second, 200*time.Millisecond) + defer cl.Close() + + h.CancelContext() + var res *CommandResult + select { + case <-time.After(20 * time.Second): + h.Fail("didn't cleanup after 20 seconds") + case res = <-resCh: + h.NoError(res.Err) + } + out := res.Stdout.String() + h.Contains(out, "Persistence:") + h.Contains(out, "file ("+dbFilename+")") +} + type testLogger struct { t *testing.T } From 2b09ade8f4dbb3ba6da10cf06014b9d49c92b018 Mon Sep 17 00:00:00 2001 From: Sai Asish Y Date: Fri, 22 May 2026 00:40:32 -0700 Subject: [PATCH 2/4] refactor(server): apply chaptersix banner suggestions --- internal/temporalcli/commands.server.go | 18 +++++++++--------- internal/temporalcli/commands.server_test.go | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/temporalcli/commands.server.go b/internal/temporalcli/commands.server.go index 2e9fe2676..bd6bed6af 100644 --- a/internal/temporalcli/commands.server.go +++ b/internal/temporalcli/commands.server.go @@ -160,20 +160,20 @@ func (t *TemporalServerStartDevCommand) run(cctx *CommandContext, args []string) defer s.Stop() cctx.Printer.Printlnf("Temporal CLI %v\n", VersionString()) - cctx.Printer.Printlnf("%-17s %v:%v", "Temporal Server:", toFriendlyIp(opts.FrontendIP), opts.FrontendPort) + cctx.Printer.Printlnf("%-21s %v:%v", "Temporal Server:", toFriendlyIp(opts.FrontendIP), opts.FrontendPort) + if t.DbFilename == "" { + cctx.Printer.Printlnf("%-21s %v", "Temporal Persistence:", "in-memory") + } else { + cctx.Printer.Printlnf("%-21s %v", "Temporal Persistence:", t.DbFilename) + } // Only print HTTP port if explicitly provided to avoid promoting the unstable HTTP API. if opts.FrontendHTTPPort > 0 { - cctx.Printer.Printlnf("%-17s %v:%v", "Temporal HTTP:", toFriendlyIp(opts.FrontendIP), opts.FrontendHTTPPort) + cctx.Printer.Printlnf("%-21s %v:%v", "Temporal HTTP:", toFriendlyIp(opts.FrontendIP), opts.FrontendHTTPPort) } if !t.Headless { - cctx.Printer.Printlnf("%-17s http://%v:%v%v", "Temporal UI:", toFriendlyIp(opts.UIIP), opts.UIPort, opts.PublicPath) - } - cctx.Printer.Printlnf("%-17s http://%v:%v/metrics", "Temporal Metrics:", toFriendlyIp(opts.FrontendIP), opts.MetricsPort) - if t.DbFilename == "" { - cctx.Printer.Printlnf("%-17s %v", "Persistence:", "in-memory (Workflow Executions are lost when the server process exits)") - } else { - cctx.Printer.Printlnf("%-17s file (%v)", "Persistence:", t.DbFilename) + cctx.Printer.Printlnf("%-21s http://%v:%v%v", "Temporal UI:", toFriendlyIp(opts.UIIP), opts.UIPort, opts.PublicPath) } + cctx.Printer.Printlnf("%-21s http://%v:%v/metrics", "Temporal Metrics:", toFriendlyIp(opts.FrontendIP), opts.MetricsPort) <-cctx.Done() if !t.Parent.Parent.LogLevel.ChangedFromDefault { // The server routinely emits various warnings on shutdown. diff --git a/internal/temporalcli/commands.server_test.go b/internal/temporalcli/commands.server_test.go index 9c111b72d..0cc89042e 100644 --- a/internal/temporalcli/commands.server_test.go +++ b/internal/temporalcli/commands.server_test.go @@ -306,7 +306,7 @@ func TestServer_StartDev_BannerPersistenceInMemory(t *testing.T) { h.NoError(res.Err) } out := res.Stdout.String() - h.Contains(out, "Persistence:") + h.Contains(out, "Temporal Persistence:") h.Contains(out, "in-memory") } @@ -346,8 +346,8 @@ func TestServer_StartDev_BannerPersistenceFile(t *testing.T) { h.NoError(res.Err) } out := res.Stdout.String() - h.Contains(out, "Persistence:") - h.Contains(out, "file ("+dbFilename+")") + h.Contains(out, "Temporal Persistence:") + h.Contains(out, dbFilename) } type testLogger struct { From e678f37aba0367c93f0c3c41c51b2b0a9bfebc36 Mon Sep 17 00:00:00 2001 From: Sai Asish Y Date: Sun, 24 May 2026 19:24:30 -0700 Subject: [PATCH 3/4] test: extend file-backed server startup timeout on Windows Signed-off-by: Sai Asish Y --- internal/temporalcli/commands.server_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/temporalcli/commands.server_test.go b/internal/temporalcli/commands.server_test.go index 0cc89042e..bfb47d475 100644 --- a/internal/temporalcli/commands.server_test.go +++ b/internal/temporalcli/commands.server_test.go @@ -324,6 +324,7 @@ func TestServer_StartDev_BannerPersistenceFile(t *testing.T) { }() var cl client.Client + // File-backed server takes longer to start due to SQLite initialization. h.EventuallyWithT(func(t *assert.CollectT) { select { case res := <-resCh: @@ -334,7 +335,7 @@ func TestServer_StartDev_BannerPersistenceFile(t *testing.T) { var err error cl, err = client.Dial(client.Options{HostPort: "127.0.0.1:" + port}) assert.NoError(t, err) - }, 3*time.Second, 200*time.Millisecond) + }, 15*time.Second, 200*time.Millisecond) defer cl.Close() h.CancelContext() From 676be6981a255d249cfdcac1c1cc7a2ae15b6125 Mon Sep 17 00:00:00 2001 From: Sai Asish Y Date: Tue, 26 May 2026 18:51:48 -0700 Subject: [PATCH 4/4] test: fix Windows file-lock cleanup in BannerPersistenceFile test Signed-off-by: Sai Asish Y --- internal/temporalcli/commands.server_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/temporalcli/commands.server_test.go b/internal/temporalcli/commands.server_test.go index bfb47d475..26b92cf60 100644 --- a/internal/temporalcli/commands.server_test.go +++ b/internal/temporalcli/commands.server_test.go @@ -316,7 +316,14 @@ func TestServer_StartDev_BannerPersistenceFile(t *testing.T) { port := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) httpPort := strconv.Itoa(devserver.MustGetFreePort("127.0.0.1")) - dbFilename := filepath.Join(t.TempDir(), "devserver-banner.sqlite") + // Use os.TempDir with an explicit defer-remove so Windows file-lock cleanup + // (os.RemoveAll in t.TempDir) does not race with a still-open SQLite handle. + dbFilename := filepath.Join(os.TempDir(), "devserver-banner-"+t.Name()+".sqlite") + t.Cleanup(func() { + _ = os.Remove(dbFilename) + _ = os.Remove(dbFilename + "-shm") + _ = os.Remove(dbFilename + "-wal") + }) resCh := make(chan *CommandResult, 1) go func() { resCh <- h.Execute("server", "start-dev", "-p", port, "--http-port", httpPort,