Phoenix: Starting watchers with `server: false`

Created on 24 Apr 2020  路  4Comments  路  Source: phoenixframework/phoenix

This might be a very specific use-case or something, but I run multiple phonix apps in an umbrella fronted by one phoenix app with a router that uses the forward directive to forward prefixes to specific endpoints.

defmodule Proxy.Router do
  use Phoenix.Router

  get        "/healthz", Proxy.Health, :check
  forward "/api", API.Endpoint
  forward "/admin", Admin.Endpoint
  forward "/", Client.Endpoint
end

So, it's all working nicely. Except that the watchers are not running if I set the server: false to those 3 endpoints.

Environment

  • Elixir version (elixir -v): 1.10
  • Phoenix version (mix deps): 1.5.0
  • NodeJS version (node -v): 1.13
  • NPM version (npm -v): Yarn
  • Operating system: Ubuntu

Expected behavior

Watchers config should be separated from the server: Boolean config

Actual behavior

Watchers are toggled via server: Boolean config

Most helpful comment

For those looking for a workaround, this helped me:

defmodule Web.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    config = Phoenix.Endpoint.Supervisor.config(:web, Web.Endpoint)

    children = [
      # Start the Telemetry supervisor
      Web.Telemetry,
      # Start the Endpoint (http/https)
      Web.Endpoint
    ]

    children = 
      if not config[:server] and config[:watcher], 
        do: children ++ watcher_children(config[:watchers]), 
        else: children

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Web.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    Web.Endpoint.config_change(changed, removed)
    :ok
  end

  defp watcher_children(watchers) do
    Enum.map(watchers, fn {cmd, args} ->
      {Phoenix.Endpoint.Watcher, watcher_args(cmd, args)}
    end)
  end

  defp watcher_args(cmd, cmd_args) do
    {args, opts} = Enum.split_while(cmd_args, &is_binary(&1))
    {cmd, args, opts}
  end
end
config :web, Web.Endpoint,
  server: false,
+ watcher: true

All 4 comments

We could support this with new config, but I would prefer to wait for more needs in the wild before committing to it. Your best bet for now is to start the webpack/asset tools yourself. Thanks!

For those looking for a workaround, this helped me:

defmodule Web.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    config = Phoenix.Endpoint.Supervisor.config(:web, Web.Endpoint)

    children = [
      # Start the Telemetry supervisor
      Web.Telemetry,
      # Start the Endpoint (http/https)
      Web.Endpoint
    ]

    children = 
      if not config[:server] and config[:watcher], 
        do: children ++ watcher_children(config[:watchers]), 
        else: children

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Web.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    Web.Endpoint.config_change(changed, removed)
    :ok
  end

  defp watcher_children(watchers) do
    Enum.map(watchers, fn {cmd, args} ->
      {Phoenix.Endpoint.Watcher, watcher_args(cmd, args)}
    end)
  end

  defp watcher_args(cmd, cmd_args) do
    {args, opts} = Enum.split_while(cmd_args, &is_binary(&1))
    {cmd, args, opts}
  end
end
config :web, Web.Endpoint,
  server: false,
+ watcher: true

I have the same issue here. Thank you @imranismail for the workaround!

I had to made some changes to that to handle bad arg error for not and and method.

defmodule Web.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    config = Phoenix.Endpoint.Supervisor.config(:web, Web.Endpoint)
    server? = Keyword.get(config, :server, false)
    watcher? = Keyword.get(config, :watcher, false)

    children = [
      # Start the Telemetry supervisor
      Web.Telemetry,
      # Start the Endpoint (http/https)
      Web.Endpoint
    ]

    children = 
      if not server? and watcher?, 
        do: children ++ watcher_children(config[:watchers]), 
        else: children

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Web.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    Web.Endpoint.config_change(changed, removed)
    :ok
  end

  defp watcher_children(watchers) do
    Enum.map(watchers, fn {cmd, args} ->
      {Phoenix.Endpoint.Watcher, watcher_args(cmd, args)}
    end)
  end

  defp watcher_args(cmd, cmd_args) do
    {args, opts} = Enum.split_while(cmd_args, &is_binary(&1))
    {cmd, args, opts}
  end
end
Was this page helpful?
0 / 5 - 0 ratings