From 94d341c46cc9296a38080129c50b256f838aeaa4 Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Wed, 26 Jun 2024 22:23:55 +1000 Subject: [PATCH] fix: `GetModuleContext()` was busy looping (#1880) By design, `RetryStreamingServerStream()` reissues the underlying RPC whenever the stream terminates, and `GetModuleContext()` was exiting immediately after sending its first response, resulting in a busy loop. --- backend/controller/controller.go | 37 +++++++++++++++++--------------- cmd/ftl/cmd_serve.go | 1 + 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/backend/controller/controller.go b/backend/controller/controller.go index eaf600bfd8..e4e6f42b91 100644 --- a/backend/controller/controller.go +++ b/backend/controller/controller.go @@ -79,6 +79,7 @@ type Config struct { RunnerTimeout time.Duration `help:"Runner heartbeat timeout." default:"10s"` ControllerTimeout time.Duration `help:"Controller heartbeat timeout." default:"10s"` DeploymentReservationTimeout time.Duration `help:"Deployment reservation timeout." default:"120s"` + ModuleUpdateFrequency time.Duration `help:"Frequency to send module updates." default:"30s"` ArtefactChunkSize int `help:"Size of each chunk streamed to the client." default:"1048576"` CommonConfig } @@ -678,26 +679,28 @@ func (s *Service) GetModuleContext(ctx context.Context, req *connect.Request[ftl cm := cf.ConfigFromContext(ctx) sm := cf.SecretsFromContext(ctx) - configs, err := cm.MapForModule(ctx, name) - if err != nil { - return connect.NewError(connect.CodeInternal, fmt.Errorf("could not get configs: %w", err)) - } - secrets, err := sm.MapForModule(ctx, name) - if err != nil { - return connect.NewError(connect.CodeInternal, fmt.Errorf("could not get secrets: %w", err)) - } - databases, err := modulecontext.DatabasesFromSecrets(ctx, name, secrets) - if err != nil { - return connect.NewError(connect.CodeInternal, fmt.Errorf("could not get databases: %w", err)) - } + for { + configs, err := cm.MapForModule(ctx, name) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("could not get configs: %w", err)) + } + secrets, err := sm.MapForModule(ctx, name) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("could not get secrets: %w", err)) + } + databases, err := modulecontext.DatabasesFromSecrets(ctx, name, secrets) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("could not get databases: %w", err)) + } - response := modulecontext.NewBuilder(name).AddConfigs(configs).AddSecrets(secrets).AddDatabases(databases).Build().ToProto() + response := modulecontext.NewBuilder(name).AddConfigs(configs).AddSecrets(secrets).AddDatabases(databases).Build().ToProto() - if err := resp.Send(response); err != nil { - return connect.NewError(connect.CodeInternal, fmt.Errorf("could not send response: %w", err)) - } + if err := resp.Send(response); err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("could not send response: %w", err)) + } - return nil + time.Sleep(s.config.ModuleUpdateFrequency) + } } // AcquireLease acquires a lease on behalf of a module. diff --git a/cmd/ftl/cmd_serve.go b/cmd/ftl/cmd_serve.go index 85aad6ad18..584d15d0e2 100644 --- a/cmd/ftl/cmd_serve.go +++ b/cmd/ftl/cmd_serve.go @@ -122,6 +122,7 @@ func (s *serveCmd) Run(ctx context.Context, projConfig projectconfig.Config) err if err := kong.ApplyDefaults(&config); err != nil { return err } + config.ModuleUpdateFrequency = time.Second * 1 scope := fmt.Sprintf("controller%d", i) controllerCtx := log.ContextWithLogger(ctx, logger.Scope(scope))