Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 30 additions & 18 deletions Sources/Container-Compose/Commands/ComposeUp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,7 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {
fatalError("unreachable")
}

private func getIPForRunningService(_ serviceName: String) async throws -> String? {
guard let projectName else { return nil }

let containerName = "\(projectName)-\(serviceName)"

private func getIPForContainer(_ containerName: String) async throws -> String? {
let container = try await ClientContainer.get(id: containerName)
let ip = container.networks.compactMap { try? CIDRAddress($0.address).address.description }.first

Expand All @@ -196,26 +192,30 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {
/// - containerName: The exact name of the container (e.g. "Assignment-Manager-API-db").
/// - timeout: Max seconds to wait before failing.
/// - interval: How often to poll (in seconds).
/// - Returns: `true` if the container reached "running" state within the timeout.
private func waitUntilServiceIsRunning(_ serviceName: String, timeout: TimeInterval = 30, interval: TimeInterval = 0.5) async throws {
guard let projectName else { return }
let containerName = "\(projectName)-\(serviceName)"

private func waitUntilContainerIsRunning(_ containerName: String, timeout: TimeInterval = 30, interval: TimeInterval = 0.5) async throws {
let deadline = Date().addingTimeInterval(timeout)
var lastStatus: RuntimeStatus?

while Date() < deadline {
let container = try? await ClientContainer.get(id: containerName)
if container?.status == .running {
return
do {
let container = try await ClientContainer.get(id: containerName)
lastStatus = container.status
if container.status == .running {
print("Container '\(containerName)' is now running.")
return
}
} catch {
// Container doesn't exist yet, keep polling
}

try await Task.sleep(nanoseconds: UInt64(interval * 1_000_000_000))
}

let statusMessage = lastStatus.map { "Last status: \($0)" } ?? "Container was never found"
throw NSError(
domain: "ContainerWait", code: 1,
userInfo: [
NSLocalizedDescriptionKey: "Timed out waiting for container '\(containerName)' to be running."
NSLocalizedDescriptionKey: "Timed out waiting for container '\(containerName)' to be running. \(statusMessage)"
])
}

Expand Down Expand Up @@ -244,8 +244,8 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {

// MARK: Compose Top Level Functions

private mutating func updateEnvironmentWithServiceIP(_ serviceName: String) async throws {
let ip = try await getIPForRunningService(serviceName)
private mutating func updateEnvironmentWithServiceIP(_ serviceName: String, containerName: String) async throws {
let ip = try await getIPForContainer(containerName)
self.containerIps[serviceName] = ip
for (key, value) in environmentVariables.map({ ($0, $1) }) where value == serviceName {
self.environmentVariables[key] = ip ?? value
Expand Down Expand Up @@ -542,6 +542,18 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {

self.containerConsoleColors[serviceName] = serviceColor

// Check if container already exists
if let existingContainer = try? await ClientContainer.get(id: containerName) {
if existingContainer.status == .running {
print("Container '\(containerName)' is already running.")
try await updateEnvironmentWithServiceIP(serviceName, containerName: containerName)
return
} else {
print("Error: Container '\(containerName)' already exists with status: \(existingContainer.status).")
return
}
}

Task { [self, serviceColor] in
@Sendable
func handleOutput(_ output: String) {
Expand All @@ -555,8 +567,8 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {
}

do {
try await waitUntilServiceIsRunning(serviceName)
try await updateEnvironmentWithServiceIP(serviceName)
try await waitUntilContainerIsRunning(containerName)
try await updateEnvironmentWithServiceIP(serviceName, containerName: containerName)
} catch {
print(error)
}
Expand Down