defmodule Compox.Docker.Services do @moduledoc """ Provides functions to work with [Compox services](`Compox.Docker.Services.Service`). """ require Logger alias Compox.Docker.Services.Service alias Compox.Docker.API.Containers @doc """ Starts [services](`t:Compox.Docker.Service.t/0`) from the `docker compose`. Each service is started independently. After all services are launch, returns the list of services updated with each container id. """ @spec start([Service.t()]) :: [Service.t()] def start(services) when is_list(services) do Enum.map(services, &start/1) end @spec start(Service.t()) :: Service.t() def start(%Service{name: name} = service) do Mix.shell().info("[compox] Starting service #{name}...") System.cmd("docker-compose", ["up", "-d", name]) container_id = Containers.get_id(name) wait_until_up(container_id) maybe_wait_until_connects(name) %{service | container_id: container_id} end @doc """ Stops the given [services](`t:Compox.Docker.Service.t/0`). In order to stop the containers, sends a `SIGKILL` message to all the container process. """ @spec stop([Service.t()]) :: :ok def stop(services) when is_list(services) do Enum.each(services, &stop/1) end @spec stop(Service.t()) :: :ok def stop(%Service{name: name, container_id: container_id}) do System.cmd("docker-compose", ["kill", name]) wait_until_down(container_id) Mix.shell().info("[compox] Service #{name} killed") end # # Private functions # defp maybe_wait_until_connects(service_name) do connect_fun = :compox |> Application.get_env(:container_upchecks) |> Keyword.get(String.to_atom(service_name)) case connect_fun.() do :ok -> :ok error -> Logger.info("[compox] waiting for #{service_name}...") Process.sleep(500) maybe_wait_until_connects(service_name) end end defp wait_until_up(container_id) do container_id |> Compox.Docker.API.Containers.running?() |> case do true -> Process.sleep(500) wait_until_up(container_id) _ -> :ok end end defp wait_until_down(container_id) do container_id |> Compox.Docker.API.Containers.running?() |> case do true -> Process.sleep(500) wait_until_down(container_id) _ -> :ok end end end