From e3c6fc87586de2d213775127a0b0c7e2591d7049 Mon Sep 17 00:00:00 2001 From: Harry Dhillon Date: Thu, 16 Oct 2025 00:26:58 -0600 Subject: [PATCH] fix: Detect and handle already running services during startup - Add `wasAlreadyRunning` flag to track if a service container was found already running. - Update service startup logic to skip starting a new container if the service is already running. - Improve user feedback in CLI with appropriate messages for running services. Signed-off-by: Harry Dhillon --- internal/service/orchestrator.go | 8 ++++++- internal/service/service.go | 36 ++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/internal/service/orchestrator.go b/internal/service/orchestrator.go index a151488..f3cabb5 100644 --- a/internal/service/orchestrator.go +++ b/internal/service/orchestrator.go @@ -208,7 +208,13 @@ func (o *Orchestrator) startServicesInParallel(ctx context.Context, serviceNames if len(containerID) > 12 { containerID = containerID[:12] } - spinner.Success(fmt.Sprintf("Started %s %s", ui.Bold(serviceName), ui.Dim(containerID))) + + // Show the appropriate message based on whether it was already running + if svc.WasAlreadyRunning() { + spinner.Success(fmt.Sprintf("%s already running %s", ui.Bold(serviceName), ui.Dim(containerID))) + } else { + spinner.Success(fmt.Sprintf("Started %s %s", ui.Bold(serviceName), ui.Dim(containerID))) + } // Track successfully started service (protected by mutex) mu.Lock() diff --git a/internal/service/service.go b/internal/service/service.go index 83c7d93..f1eaad8 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -50,13 +50,14 @@ type Service struct { Config config.Service // Service configuration from ork.yml // Runtime state - state State // Current service state - healthStatus HealthStatus // Current health status - containerID string // Docker container ID (when running) - networkID string // Network ID the service is connected to - startedAt time.Time // When the service was started - stoppedAt time.Time // When the service was stopped - lastError error // Last error encountered + state State // Current service state + healthStatus HealthStatus // Current health status + containerID string // Docker container ID (when running) + networkID string // Network ID the service is connected to + startedAt time.Time // When the service was started + stoppedAt time.Time // When the service was stopped + lastError error // Last error encountered + wasAlreadyRunning bool // True if the container was found already running (not newly started) // Synchronization mu sync.RWMutex // Protects state changes @@ -95,6 +96,7 @@ func (s *Service) Start(ctx context.Context, client *docker.Client, networkID st s.state = StateStarting s.healthStatus = HealthStarting s.lastError = nil + s.wasAlreadyRunning = false // Reset flag - assume we'll start a new container // Check if a container already exists if err := s.checkAndCleanupExistingContainer(ctx, client); err != nil { @@ -103,6 +105,12 @@ func (s *Service) Start(ctx context.Context, client *docker.Client, networkID st return err } + // If the service is already running (discovered by checkAndCleanupExistingContainer), + // return success without trying to start a new container + if s.state == StateRunning { + return nil + } + // Load environment variables envVars, err := config.LoadAllEnvForService(s.Name, s.Config.Env) if err != nil { @@ -252,6 +260,13 @@ func (s *Service) IsHealthy() bool { return s.GetHealthStatus() == HealthHealthy } +// WasAlreadyRunning returns true if the service was found already running (not newly started) +func (s *Service) WasAlreadyRunning() bool { + s.mu.RLock() + defer s.mu.RUnlock() + return s.wasAlreadyRunning +} + // ============================================================================ // Health Check Methods // ============================================================================ @@ -371,10 +386,13 @@ func (s *Service) checkAndCleanupExistingContainer(ctx context.Context, client * if container.Labels["ork.service"] == s.Name { // Check if it's running if strings.HasPrefix(container.Status, "Up") { - // Update our state to match reality + // Update our state to match reality - service is already running s.containerID = container.ID s.state = StateRunning - return fmt.Errorf("service %s is already running (container: %s)", s.Name, container.ID) + s.startedAt = time.Now() // Approximate start time + s.wasAlreadyRunning = true // Mark as already running (not newly started) + // Return nil (success) - the service is already in the desired state + return nil } // Container exists but is stopped - remove it