From 2f9be529107f36942ab64e39d035583befa08441 Mon Sep 17 00:00:00 2001 From: Siva Date: Tue, 5 May 2026 16:49:28 +0530 Subject: [PATCH 1/2] fix: send SIGHUP to MCP container after initial deploy --- .../orchestrator/swarm/mcp_config_resource.go | 7 +++++++ .../internal/orchestrator/swarm/service_instance.go | 2 ++ .../orchestrator/swarm/service_instance_spec.go | 11 +++++++++++ 3 files changed, 20 insertions(+) diff --git a/server/internal/orchestrator/swarm/mcp_config_resource.go b/server/internal/orchestrator/swarm/mcp_config_resource.go index bcb2620a..a0c7cd99 100644 --- a/server/internal/orchestrator/swarm/mcp_config_resource.go +++ b/server/internal/orchestrator/swarm/mcp_config_resource.go @@ -254,6 +254,13 @@ func (r *MCPConfigResource) writeUserFileIfNeeded(fs afero.Fs, usersPath string) // return nil — the config file is already correct on disk and will be // picked up on the next container restart. Injector failures are returned // as errors since they indicate a systemic problem. +// PostDeploy is called by ServiceInstanceResource after the container is confirmed +// running. It sends SIGHUP to trigger a config reload, handling VirtioFS +// bind-mount propagation delays on initial provisioning. +func (r *MCPConfigResource) PostDeploy(ctx context.Context, rc *resource.Context) { + _ = r.signalConfigReload(ctx, rc) +} + func (r *MCPConfigResource) signalConfigReload(ctx context.Context, rc *resource.Context) error { dockerClient, err := do.Invoke[*docker.Docker](rc.Injector) if err != nil { diff --git a/server/internal/orchestrator/swarm/service_instance.go b/server/internal/orchestrator/swarm/service_instance.go index a7775074..25786566 100644 --- a/server/internal/orchestrator/swarm/service_instance.go +++ b/server/internal/orchestrator/swarm/service_instance.go @@ -203,6 +203,8 @@ func (s *ServiceInstanceResource) deploy(ctx context.Context, rc *resource.Conte Str("service_id", res.ServiceID). Msg("service instance started successfully") + spec.PostDeploy(ctx, rc) + // Transition state to "running" immediately after successful deployment. // This mirrors the database instance pattern where state is set // deterministically within the resource activity, not deferred to the monitor. diff --git a/server/internal/orchestrator/swarm/service_instance_spec.go b/server/internal/orchestrator/swarm/service_instance_spec.go index 2b46793f..43376887 100644 --- a/server/internal/orchestrator/swarm/service_instance_spec.go +++ b/server/internal/orchestrator/swarm/service_instance_spec.go @@ -90,6 +90,17 @@ func (s *ServiceInstanceSpecResource) TypeDependencies() []resource.Type { return nil } +// PostDeploy is called by ServiceInstanceResource after the container is confirmed +// running. Each service type can trigger any necessary post-start actions here. +func (s *ServiceInstanceSpecResource) PostDeploy(ctx context.Context, rc *resource.Context) { + switch s.ServiceSpec.ServiceType { + case "mcp": + if mcpCfg, err := resource.FromContext[*MCPConfigResource](rc, MCPConfigResourceIdentifier(s.ServiceInstanceID)); err == nil { + mcpCfg.PostDeploy(ctx, rc) + } + } +} + func (s *ServiceInstanceSpecResource) Refresh(ctx context.Context, rc *resource.Context) error { network, err := resource.FromContext[*Network](rc, NetworkResourceIdentifier(s.DatabaseNetworkID)) if err != nil { From 44c88714640748074839da78b12ef6add6d8e584 Mon Sep 17 00:00:00 2001 From: Siva Date: Tue, 5 May 2026 18:14:26 +0530 Subject: [PATCH 2/2] addressing AI review comments --- .../internal/orchestrator/swarm/mcp_config_resource.go | 10 +++++++++- .../orchestrator/swarm/service_instance_spec.go | 9 +++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/server/internal/orchestrator/swarm/mcp_config_resource.go b/server/internal/orchestrator/swarm/mcp_config_resource.go index a0c7cd99..fda628c5 100644 --- a/server/internal/orchestrator/swarm/mcp_config_resource.go +++ b/server/internal/orchestrator/swarm/mcp_config_resource.go @@ -258,7 +258,15 @@ func (r *MCPConfigResource) writeUserFileIfNeeded(fs afero.Fs, usersPath string) // running. It sends SIGHUP to trigger a config reload, handling VirtioFS // bind-mount propagation delays on initial provisioning. func (r *MCPConfigResource) PostDeploy(ctx context.Context, rc *resource.Context) { - _ = r.signalConfigReload(ctx, rc) + logger, err := do.Invoke[zerolog.Logger](rc.Injector) + if err != nil { + return + } + if err := r.signalConfigReload(ctx, rc); err != nil { + logger.Warn().Err(err). + Str("service_instance_id", r.ServiceInstanceID). + Msg("post-deploy config reload signal failed") + } } func (r *MCPConfigResource) signalConfigReload(ctx context.Context, rc *resource.Context) error { diff --git a/server/internal/orchestrator/swarm/service_instance_spec.go b/server/internal/orchestrator/swarm/service_instance_spec.go index 43376887..8bb310bb 100644 --- a/server/internal/orchestrator/swarm/service_instance_spec.go +++ b/server/internal/orchestrator/swarm/service_instance_spec.go @@ -95,9 +95,14 @@ func (s *ServiceInstanceSpecResource) TypeDependencies() []resource.Type { func (s *ServiceInstanceSpecResource) PostDeploy(ctx context.Context, rc *resource.Context) { switch s.ServiceSpec.ServiceType { case "mcp": - if mcpCfg, err := resource.FromContext[*MCPConfigResource](rc, MCPConfigResourceIdentifier(s.ServiceInstanceID)); err == nil { - mcpCfg.PostDeploy(ctx, rc) + mcpCfg, err := resource.FromContext[*MCPConfigResource](rc, MCPConfigResourceIdentifier(s.ServiceInstanceID)) + if err != nil { + log.Warn().Err(err). + Str("service_instance_id", s.ServiceInstanceID). + Msg("skipping MCP post-deploy hook: MCP config resource unavailable") + return } + mcpCfg.PostDeploy(ctx, rc) } }