Skip to content
This repository was archived by the owner on Jul 16, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config :preview,
queue_id: "dummy",
queue_producer: Broadway.DummyProducer,
queue_concurrency: 2,
queue_enabled: true,
package_store_impl: Preview.Package.DefaultStore,
package_updater_impl: Preview.Package.Updater,
hex_impl: Preview.Hex.HTTP,
Expand Down
39 changes: 28 additions & 11 deletions config/runtime.exs
Original file line number Diff line number Diff line change
@@ -1,18 +1,39 @@
import Config

if config_env() == :prod do
queue_enabled =
case System.get_env("PREVIEW_QUEUE_ENABLED", "true") do
"true" ->
true

"false" ->
false

value ->
raise "invalid PREVIEW_QUEUE_ENABLED #{inspect(value)}; expected \"true\" or \"false\""
end

config :preview,
host: System.fetch_env!("PREVIEW_HOST"),
repo_url: System.fetch_env!("PREVIEW_REPO_URL"),
repo_public_key: System.fetch_env!("PREVIEW_REPO_PUBLIC_KEY"),
queue_id: System.fetch_env!("PREVIEW_QUEUE_ID"),
queue_concurrency: String.to_integer(System.fetch_env!("PREVIEW_QUEUE_CONCURRENCY")),
fastly_key: System.fetch_env!("PREVIEW_FASTLY_KEY"),
fastly_repo: System.fetch_env!("PREVIEW_FASTLY_REPO")
queue_enabled: queue_enabled

config :preview, :repo_bucket,
implementation: Preview.Storage.S3,
name: System.fetch_env!("PREVIEW_REPO_BUCKET")
if queue_enabled do
config :preview,
queue_id: System.fetch_env!("PREVIEW_QUEUE_ID"),
queue_concurrency: String.to_integer(System.fetch_env!("PREVIEW_QUEUE_CONCURRENCY")),
fastly_key: System.fetch_env!("PREVIEW_FASTLY_KEY"),
fastly_repo: System.fetch_env!("PREVIEW_FASTLY_REPO")

config :preview, :repo_bucket,
implementation: Preview.Storage.S3,
name: System.fetch_env!("PREVIEW_REPO_BUCKET")

config :ex_aws,
access_key_id: System.fetch_env!("PREVIEW_AWS_ACCESS_KEY_ID"),
secret_access_key: System.fetch_env!("PREVIEW_AWS_ACCESS_KEY_SECRET")
end

config :preview, :preview_bucket,
implementation: Preview.Storage.GCS,
Expand All @@ -23,10 +44,6 @@ if config_env() == :prod do
url: [host: System.fetch_env!("PREVIEW_HOST")],
secret_key_base: System.fetch_env!("PREVIEW_SECRET_KEY_BASE")

config :ex_aws,
access_key_id: System.fetch_env!("PREVIEW_AWS_ACCESS_KEY_ID"),
secret_access_key: System.fetch_env!("PREVIEW_AWS_ACCESS_KEY_SECRET")

config :sentry,
dsn: System.fetch_env!("PREVIEW_SENTRY_DSN"),
environment_name: System.fetch_env!("PREVIEW_ENV")
Expand Down
17 changes: 10 additions & 7 deletions lib/preview/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,26 @@ defmodule Preview.Application do
:logger.add_handler(:my_sentry_handler, Sentry.LoggerHandler, %{})
setup_tmp_dir()

children = [
children = children(Application.fetch_env!(:preview, :queue_enabled))

opts = [strategy: :one_for_one, name: Preview.Supervisor]
Supervisor.start_link(children, opts)
end

def children(queue_enabled) when is_boolean(queue_enabled) do
common = [
Preview.TmpDir,
PreviewWeb.Telemetry,
{Phoenix.PubSub, name: Preview.PubSub},
{Task.Supervisor, name: Preview.Tasks},
{Finch, name: Preview.Finch, pools: finch_pools()},
goth_spec(),
{Preview.Debouncer, name: Preview.Debouncer},
Preview.Queue,
PreviewWeb.Endpoint,
package_spec()
]

# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Preview.Supervisor]
Supervisor.start_link(children, opts)
queue = [{Preview.Debouncer, name: Preview.Debouncer}, Preview.Queue]
common ++ if(queue_enabled, do: queue, else: [])
end

# Tell Phoenix to update the endpoint configuration
Expand Down
124 changes: 124 additions & 0 deletions test/preview/application_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
defmodule Preview.ApplicationTest do
use ExUnit.Case, async: true

alias Preview.Application

test "queue children can be disabled without removing the web endpoint" do
enabled = child_ids(Application.children(true))
disabled = child_ids(Application.children(false))

assert Preview.Queue in enabled
assert Preview.Debouncer in enabled
refute Preview.Queue in disabled
refute Preview.Debouncer in disabled
assert PreviewWeb.Endpoint in enabled
assert PreviewWeb.Endpoint in disabled
end

test "disabled production configuration does not require queue credentials" do
elixir = System.find_executable("elixir")
erl = System.find_executable("erl")
path = [Path.dirname(elixir), Path.dirname(erl), "/usr/bin", "/bin"] |> Enum.uniq()

env = [
"PATH=#{Enum.join(path, ":")}",
"PREVIEW_QUEUE_ENABLED=false",
"PREVIEW_HOST=preview.hex.pm",
"PREVIEW_REPO_URL=https://repo.hex.pm",
"PREVIEW_REPO_PUBLIC_KEY=public-key",
"PREVIEW_BUCKET=preview-bucket",
"PREVIEW_PORT=4005",
"PREVIEW_SECRET_KEY_BASE=secret-key-base",
"PREVIEW_SENTRY_DSN=sentry-dsn",
"PREVIEW_ENV=prod",
"BEAM_PORT=14005"
]

expression = ~S|Config.Reader.read!("config/runtime.exs", env: :prod); IO.write("configured")|

assert {"configured", 0} =
System.cmd(System.find_executable("env"), ["-i" | env] ++ [elixir, "-e", expression])
end

test "production configuration defaults to an enabled queue" do
env = runtime_env() ++ queue_env()

expression =
~S"""
config = Config.Reader.read!("config/runtime.exs", env: :prod)
preview = config[:preview]
ex_aws = config[:ex_aws]

IO.write(
Enum.join(
[
preview[:queue_id],
preview[:queue_concurrency],
preview[:fastly_key],
preview[:fastly_repo],
preview[:repo_bucket][:name],
ex_aws[:access_key_id],
ex_aws[:secret_access_key]
],
"|"
)
)
"""

assert {"queue|10|fastly-key|fastly-repo|repo-bucket|aws-key|aws-secret", 0} =
System.cmd(
System.find_executable("env"),
["-i" | env] ++ [System.find_executable("elixir"), "-e", expression]
)
end

test "production configuration rejects invalid queue settings" do
env = ["PREVIEW_QUEUE_ENABLED=invalid" | runtime_env()]
expression = ~S|Config.Reader.read!("config/runtime.exs", env: :prod)|

assert {output, status} =
System.cmd(
System.find_executable("env"),
["-i" | env] ++ [System.find_executable("elixir"), "-e", expression],
stderr_to_stdout: true
)

assert status != 0
assert output =~ "invalid PREVIEW_QUEUE_ENABLED"
end

defp runtime_env do
elixir = System.find_executable("elixir")
erl = System.find_executable("erl")
path = [Path.dirname(elixir), Path.dirname(erl), "/usr/bin", "/bin"] |> Enum.uniq()

[
"PATH=#{Enum.join(path, ":")}",
"PREVIEW_HOST=preview.hex.pm",
"PREVIEW_REPO_URL=https://repo.hex.pm",
"PREVIEW_REPO_PUBLIC_KEY=public-key",
"PREVIEW_BUCKET=preview-bucket",
"PREVIEW_PORT=4005",
"PREVIEW_SECRET_KEY_BASE=secret-key-base",
"PREVIEW_SENTRY_DSN=sentry-dsn",
"PREVIEW_ENV=prod",
"BEAM_PORT=14005"
]
end

defp queue_env do
[
"PREVIEW_QUEUE_ID=queue",
"PREVIEW_QUEUE_CONCURRENCY=10",
"PREVIEW_FASTLY_KEY=fastly-key",
"PREVIEW_FASTLY_REPO=fastly-repo",
"PREVIEW_REPO_BUCKET=repo-bucket",
"PREVIEW_AWS_ACCESS_KEY_ID=aws-key",
"PREVIEW_AWS_ACCESS_KEY_SECRET=aws-secret"
]
end

defp child_ids(children) do
MapSet.new(children, fn child -> Supervisor.child_spec(child, []).id end)
end
end