Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Oban generator to phx.new #5970

Closed
wants to merge 4 commits into from
Closed
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
3 changes: 3 additions & 0 deletions guides/introduction/packages_glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ You will also work with the following:
* [Swoosh](https://hexdocs.pm/swoosh) - a library for composing,
delivering and testing emails, also used by `mix phx.gen.auth`

* [Oban](https://hexdocs.pm/oban) - async, distributed background job
system that uses SQL for job persistence

When peeking under the covers, you will find these libraries play
an important role in Phoenix applications:

Expand Down
6 changes: 6 additions & 0 deletions installer/lib/mix/tasks/phx.new.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ defmodule Mix.Tasks.Phx.New do

* `--no-mailer` - do not generate Swoosh mailer files

* `--no-oban` — do not include Oban for async background jobs.
Oban requires `ecto`, and either `postgres` or `sqlite3` for job
persistence. Oban won't be included if the `--no-ecto` flag or an
incompatible database is selected

* `--no-tailwind` - do not include tailwind dependencies and assets.
The generated markup will still include Tailwind CSS classes, those
are left-in as reference for the subsequent styling of your layout
Expand Down Expand Up @@ -137,6 +142,7 @@ defmodule Mix.Tasks.Phx.New do
verbose: :boolean,
live: :boolean,
dashboard: :boolean,
oban: :boolean,
install: :boolean,
prefix: :string,
mailer: :boolean,
Expand Down
12 changes: 12 additions & 0 deletions installer/lib/phx_new/generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ defmodule Phx.New.Generator do
{adapter_app, adapter_module, adapter_config} =
get_ecto_adapter(db, String.downcase(project.app), project.app_mod)

# Oban requires ecto, and is only compatible with `postgres`
# or `sqlite3` adapters.
oban = ecto and adapter_app in ~w(postgrex ecto_sqlite3)a and Keyword.get(opts, :oban, true)

oban_engine = get_oban_engine(adapter_app)

{web_adapter_app, web_adapter_vsn, web_adapter_module, web_adapter_docs} = get_web_adapter(web_adapter)

pubsub_server = get_pubsub_server(project.app_mod)
Expand Down Expand Up @@ -228,6 +234,8 @@ defmodule Phx.New.Generator do
live: live,
live_comment: if(live, do: nil, else: "// "),
dashboard: dashboard,
oban: oban,
oban_engine: inspect(oban_engine),
gettext: gettext,
adapter_app: adapter_app,
adapter_module: adapter_module,
Expand Down Expand Up @@ -304,6 +312,10 @@ defmodule Phx.New.Generator do
Mix.raise("Unknown database #{inspect(db)}")
end

defp get_oban_engine(:postgrex), do: Oban.Engines.Basic
defp get_oban_engine(:ecto_sqlite3), do: Oban.Engines.Lite
defp get_oban_engine(_other), do: :none

defp get_web_adapter("cowboy"), do: {:plug_cowboy, "~> 2.7", Phoenix.Endpoint.Cowboy2Adapter, "https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html"}
defp get_web_adapter("bandit"), do: {:bandit, "~> 1.5", Bandit.PhoenixAdapter, "https://hexdocs.pm/bandit/Bandit.html#t:options/0"}
defp get_web_adapter(other), do: Mix.raise("Unknown web adapter #{inspect(other)}")
Expand Down
26 changes: 26 additions & 0 deletions installer/lib/phx_new/oban.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Phx.New.Oban do
@moduledoc false

use Phx.New.Generator

alias Phx.New.Project

template(:new, [
{:eex, :app,
"phx_oban/oban.ex": "lib/:app/oban.ex",
"phx_oban/migration.exs": "priv/repo/migrations/0_add_oban_tables.exs"}
])

def prepare_project(%Project{} = project) do
app_path = Path.expand(project.base_path)
project_path = Path.dirname(Path.dirname(app_path))

%Project{project | in_umbrella?: true, app_path: app_path, project_path: project_path}
end

def generate(%Project{} = project) do
inject_umbrella_config_defaults(project)
copy_from(project, __MODULE__, :new)
project
end
end
4 changes: 4 additions & 0 deletions installer/lib/phx_new/project.ex
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ defmodule Phx.New.Project do
Keyword.fetch!(binding, :mailer)
end

def oban?(%Project{binding: binding}) do
Keyword.fetch!(binding, :oban)
end

def verbose?(%Project{opts: opts}) do
Keyword.get(opts, :verbose, false)
end
Expand Down
11 changes: 11 additions & 0 deletions installer/lib/phx_new/single.ex
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ defmodule Phx.New.Single do
{:eex, :app, "phx_mailer/lib/app_name/mailer.ex": "lib/:app/mailer.ex"}
])

template(:oban, [
{:eex, :app,
"phx_oban/oban.ex": "lib/:app/oban.ex",
"phx_oban/migration.exs": "priv/repo/migrations/0_add_oban_tables.exs"}
])

def prepare_project(%Project{app: app, base_path: base_path} = project) when not is_nil(app) do
if in_umbrella?(base_path) do
%Project{project | in_umbrella?: true, project_path: Path.dirname(Path.dirname(base_path))}
Expand Down Expand Up @@ -138,6 +144,7 @@ defmodule Phx.New.Single do
if Project.html?(project), do: gen_html(project)
if Project.mailer?(project), do: gen_mailer(project)
if Project.gettext?(project), do: gen_gettext(project)
if Project.oban?(project), do: gen_oban(project)

gen_assets(project)
project
Expand Down Expand Up @@ -177,4 +184,8 @@ defmodule Phx.New.Single do
def gen_mailer(%Project{} = project) do
copy_from(project, __MODULE__, :mailer)
end

def gen_oban(%Project{} = project) do
copy_from(project, __MODULE__, :oban)
end
end
2 changes: 2 additions & 0 deletions installer/templates/phx_ecto/data_case.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ defmodule <%= @app_module %>.DataCase do
quote do
alias <%= @app_module %>.Repo

use Oban.Testing, repo: <%= @app_module %>.Repo

import Ecto
import Ecto.Changeset
import Ecto.Query
Expand Down
13 changes: 13 additions & 0 deletions installer/templates/phx_oban/migration.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule <%= @app_module %>.Repo.Migrations.AddObanTables do
use Ecto.Migration

def up do
Oban.Migration.up(version: 12)
end

# We specify `version: 1` in `down`, ensuring that we'll roll all the way back down if
# necessary, regardless of which version we've migrated `up` to.
def down do
Oban.Migration.down(version: 1)
end
end
3 changes: 3 additions & 0 deletions installer/templates/phx_oban/oban.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule <%= @app_module %>.Oban do
use Oban, otp_app: :<%= @app_name %>
end
15 changes: 14 additions & 1 deletion installer/templates/phx_single/config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,20 @@ config :<%= @app_name %>, <%= @endpoint_module %>,
#
# For production it's recommended to configure a different adapter
# at the `config/runtime.exs`.
config :<%= @app_name %>, <%= @app_module %>.Mailer, adapter: Swoosh.Adapters.Local<% end %><%= if @javascript do %>
config :<%= @app_name %>, <%= @app_module %>.Mailer, adapter: Swoosh.Adapters.Local<% end %><%= if @oban do %>

# Configures Oban for background jobs
#
# A single `default` queue is configured to run 10 jobs concurrently,
# and executed jobs are retained for an hour before deletion.
config :<%= @app_name %>, <%= @app_module %>.Oban,
engine: <%= @oban_engine %>,
repo: <%= @app_module %>.Repo,
queues: [default: 10],
plugins: [
{Oban.Plugins.Pruner, max_age: 3_600},
{Oban.Plugins.Cron, crontab: []}
]<% end %><%= if @javascript do %>

# Configure esbuild (the version is required)
config :esbuild,
Expand Down
5 changes: 4 additions & 1 deletion installer/templates/phx_single/config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ config :<%= @app_name %>, <%= @app_module %>.Mailer,
adapter: Swoosh.Adapters.Test

# Disable swoosh api client as it is only required for production adapters
config :swoosh, :api_client, false<% end %>
config :swoosh, :api_client, false<% end %><%= if @oban do %>

# In test we don't run queues, plugins, or execute jobs
config :<%= @app_name %>, <%= @app_module %>.Oban, testing: :manual<% end %>

# Print only warnings and errors during test
config :logger, level: :warning
Expand Down
3 changes: 2 additions & 1 deletion installer/templates/phx_single/lib/app_name/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ defmodule <%= @app_module %>.Application do
<%= @app_module %>.Repo,<% end %><%= if @adapter_app == :ecto_sqlite3 do %>
{Ecto.Migrator,
repos: Application.fetch_env!(<%= inspect(String.to_atom(@app_name)) %>, :ecto_repos),
skip: skip_migrations?()},<% end %>
skip: skip_migrations?()},<% end %><%= if @oban do %>
<%= @app_module %>.Oban,<% end %>
{DNSCluster, query: Application.get_env(<%= inspect(String.to_atom(@app_name)) %>, :dns_cluster_query) || :ignore},
{Phoenix.PubSub, name: <%= @app_module %>.PubSub},
# Start a worker by calling: <%= @app_module %>.Worker.start_link(arg)
Expand Down
3 changes: 2 additions & 1 deletion installer/templates/phx_single/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ defmodule <%= @app_module %>.MixProject do
# TODO bump on release to {:phoenix_live_view, "~> 1.0.0"},
{:phoenix_live_view, "~> 1.0.0-rc.1", override: true},
{:floki, ">= 0.30.0", only: :test},<% end %><%= if @dashboard do %>
{:phoenix_live_dashboard, "~> 0.8.3"},<% end %><%= if @javascript do %>
{:phoenix_live_dashboard, "~> 0.8.3"},<% end %><%= if @oban do %>
{:oban, "~> 2.18"},<% end %><%= if @javascript do %>
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},<% end %><%= if @css do %>
{:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
{:heroicons,
Expand Down
3 changes: 2 additions & 1 deletion installer/templates/phx_umbrella/apps/app_name/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ defmodule <%= @app_module %>.MixProject do
{:<%= @adapter_app %>, ">= 0.0.0"},
{:jason, "~> 1.2"}<% end %><%= if @mailer do %>,
{:swoosh, "~> 1.16"},
{:req, "~> 0.5.4"}<% end %>
{:req, "~> 0.5.4"}<% end %><%= if @oban do %>,
{:oban, "~> 2.18"}<% end %>
]
end

Expand Down
26 changes: 26 additions & 0 deletions installer/test/phx_new_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,32 @@ defmodule Mix.Tasks.Phx.NewTest do
"config :swoosh, api_client: Swoosh.ApiClient.Req"
end)

# Oban
assert_file("phx_blog/mix.exs", fn file ->
assert file =~ "{:oban, \"~> 2.18\"}"
end)

assert_file("phx_blog/lib/phx_blog/oban.ex", fn file ->
assert file =~ "defmodule PhxBlog.Oban do"
assert file =~ "use Oban, otp_app: :phx_blog"
end)

assert_file("phx_blog/config/config.exs", fn file ->
assert file =~ "config :phx_blog, PhxBlog.Oban,"
assert file =~ "engine: Oban.Engines.Basic"
assert file =~ "repo: PhxBlog.Repo"
end)

assert_file("phx_blog/config/test.exs", fn file ->
assert file =~ "config :phx_blog, PhxBlog.Oban, testing: :manual"
end)

assert_file("phx_blog/priv/repo/migrations/0_add_oban_tables.exs", fn file ->
assert file =~ "defmodule PhxBlog.Repo.Migrations.AddObanTables"
assert file =~ "Oban.Migration.up(version: 12)"
assert file =~ "Oban.Migration.down(version: 1)"
end)

# Install dependencies?
assert_received {:mix_shell, :yes?, ["\nFetch and install dependencies?"]}

Expand Down
Loading