From c531981886515d17516f1091916ec36fc762e73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 11 Jun 2026 16:40:01 +0200 Subject: [PATCH 1/2] fix(examples): wait for emulator port to open before executing samples --- examples/emulator_runner.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/emulator_runner.go b/examples/emulator_runner.go index 59b5ce01..366d71b6 100644 --- a/examples/emulator_runner.go +++ b/examples/emulator_runner.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "log" + "net" "os" "time" @@ -107,19 +108,29 @@ func startEmulator() error { if err := cli.ContainerStart(ctx, containerId, container.StartOptions{}); err != nil { return err } - // Wait max 10 seconds or until the emulator is running. - for c := 0; c < 20; c++ { - // Always wait at least 500 milliseconds to ensure that the emulator is actually ready, as the - // state can be reported as ready, while the emulator (or network interface) is actually not ready. - <-time.After(500 * time.Millisecond) + // Wait max 10 seconds or until the emulator is running and port 9010 is open. + var portReady bool + for c := 0; c < 40; c++ { resp, err := cli.ContainerInspect(ctx, containerId) if err != nil { return fmt.Errorf("failed to inspect container state: %v", err) } if resp.State.Running { - break + // Try to connect to localhost:9010 + conn, err := net.DialTimeout("tcp", "localhost:9010", 250*time.Millisecond) + if err == nil { + _ = conn.Close() + portReady = true + break + } } + <-time.After(250 * time.Millisecond) } + if !portReady { + return fmt.Errorf("emulator did not start listening on port 9010 in time") + } + // Give the emulator gRPC server a moment to fully initialize after the TCP port opens. + <-time.After(1500 * time.Millisecond) return nil } From 9f2c860fd401a5df5abb2e8b892cfaf65ed3b67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 12 Jun 2026 18:15:53 +0200 Subject: [PATCH 2/2] chore: address review comments and add polling --- examples/emulator_runner.go | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/examples/emulator_runner.go b/examples/emulator_runner.go index 366d71b6..6cc7edf5 100644 --- a/examples/emulator_runner.go +++ b/examples/emulator_runner.go @@ -31,6 +31,8 @@ import ( "github.com/docker/docker/api/types/image" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) var cli *client.Client @@ -71,7 +73,7 @@ func RunSampleOnEmulatorWithDialect(sample func(string, string, string) error, d func startEmulator() error { ctx := context.Background() - if err := os.Setenv("SPANNER_EMULATOR_HOST", "localhost:9010"); err != nil { + if err := os.Setenv("SPANNER_EMULATOR_HOST", "127.0.0.1:9010"); err != nil { return err } @@ -116,23 +118,39 @@ func startEmulator() error { return fmt.Errorf("failed to inspect container state: %v", err) } if resp.State.Running { - // Try to connect to localhost:9010 - conn, err := net.DialTimeout("tcp", "localhost:9010", 250*time.Millisecond) + // Try to connect to 127.0.0.1:9010 + conn, err := net.DialTimeout("tcp", "127.0.0.1:9010", 250*time.Millisecond) if err == nil { _ = conn.Close() portReady = true break } } - <-time.After(250 * time.Millisecond) + time.Sleep(250 * time.Millisecond) } if !portReady { return fmt.Errorf("emulator did not start listening on port 9010 in time") } - // Give the emulator gRPC server a moment to fully initialize after the TCP port opens. - <-time.After(1500 * time.Millisecond) + return waitForGRPC(ctx) +} - return nil +func waitForGRPC(ctx context.Context) error { + instanceAdmin, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + return fmt.Errorf("failed to create instance admin client: %v", err) + } + defer instanceAdmin.Close() + + for c := 0; c < 40; c++ { + _, err := instanceAdmin.GetInstance(ctx, &instancepb.GetInstanceRequest{ + Name: "projects/p/instances/i", + }) + if err == nil || status.Code(err) == codes.NotFound { + return nil + } + time.Sleep(100 * time.Millisecond) + } + return fmt.Errorf("emulator gRPC server did not start in time") } func createInstance(projectId, instanceId string) error {