From dd06c6b63a3d2ea50a667e76865853c23826d7fb Mon Sep 17 00:00:00 2001 From: Norbert Melzer Date: Fri, 24 Feb 2023 13:22:24 +0100 Subject: [PATCH 1/6] refactor: extract after-compile --- lib/que/worker.ex | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/que/worker.ex b/lib/que/worker.ex index ac77202..3b83262 100644 --- a/lib/que/worker.ex +++ b/lib/que/worker.ex @@ -136,7 +136,6 @@ defmodule Que.Worker do - @doc """ Checks if the specified module is a valid Que Worker @@ -181,13 +180,27 @@ defmodule Que.Worker do end end + def __after_compile__(%{module: module}, _bytecode) do + # Raises error if the Worker doesn't export a perform/1 method + unless Module.defines?(module, {:perform, 1}) do + raise Que.Error.InvalidWorker, + "#{ExUtils.Module.name(module)} must export a perform/1 method" + end + + concurrency = module.concurrency() + # Raise error if the concurrency option in invalid + unless concurrency == :infinity or (is_integer(concurrency) and concurrency > 0) do + raise Que.Error.InvalidWorker, + "#{ExUtils.Module.name(module)} has an invalid concurrency value" + end + end @doc false defmacro __using__(opts \\ []) do quote bind_quoted: [opts: opts] do - @after_compile __MODULE__ + @after_compile Que.Worker @concurrency opts[:concurrency] || 1 @@ -218,22 +231,6 @@ defmodule Que.Worker do - # Make sure the Worker is valid - def __after_compile__(_env, _bytecode) do - - # Raises error if the Worker doesn't export a perform/1 method - unless Module.defines?(__MODULE__, {:perform, 1}) do - raise Que.Error.InvalidWorker, - "#{ExUtils.Module.name(__MODULE__)} must export a perform/1 method" - end - - - # Raise error if the concurrency option in invalid - unless @concurrency == :infinity or (is_integer(@concurrency) and @concurrency > 0) do - raise Que.Error.InvalidWorker, - "#{ExUtils.Module.name(__MODULE__)} has an invalid concurrency value" - end - end end end From 3d929f4ed4c073895daa7abb486a9c9445caa67d Mon Sep 17 00:00:00 2001 From: Zack Kollar Date: Fri, 23 Feb 2024 23:36:24 -0500 Subject: [PATCH 2/6] :hammer: Fix deprecated config usage --- config/config.exs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/config/config.exs b/config/config.exs index fe3ef03..7c0a7e8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,6 +1,6 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. -use Mix.Config +import Config # This configuration is loaded before any dependency and is restricted # to this project. If another project depends on this project, this @@ -21,17 +21,13 @@ use Mix.Config # config :logger, level: :info # - config :mnesia, - dir: '.mnesia/#{Mix.env}/#{node()}' - + dir: ~c".mnesia/#{Mix.env()}/#{node()}" - -if Mix.env == :test do +if Mix.env() == :test do config :que, log_level: :medium end - # It is also possible to import configuration files, relative to this # directory. For example, you can emulate configuration per environment # by uncommenting the line below and defining dev.exs, test.exs and such. From 7b7bb82a58957613f51fa0491ffa9d8336e64ad9 Mon Sep 17 00:00:00 2001 From: Zack Kollar Date: Fri, 23 Feb 2024 23:36:58 -0500 Subject: [PATCH 3/6] :hammer: Update Supervisor usage --- lib/que/supervisor.ex | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/que/supervisor.ex b/lib/que/supervisor.ex index ce1baba..6250f73 100644 --- a/lib/que/supervisor.ex +++ b/lib/que/supervisor.ex @@ -7,32 +7,25 @@ defmodule Que.Supervisor do you absolutely know what you're doing. """ - - - @doc """ Starts the Supervision Tree for `Que` """ - @spec start_link() :: Supervisor.on_start + @spec start_link() :: Supervisor.on_start() def start_link do # Initialize Mnesia DB for Jobs - Que.Persistence.initialize + Que.Persistence.initialize() # Start Supervision Tree Supervisor.start_link(__MODULE__, :ok, name: __MODULE__) end - - - @doc false def init(:ok) do children = [ - supervisor(Task.Supervisor, [[name: Que.TaskSupervisor]]), - supervisor(Que.ServerSupervisor, []) + {Task.Supervisor, name: Que.TaskSupervisor}, + {Que.ServerSupervisor, []} ] - supervise(children, strategy: :one_for_one) + Supervisor.init(children, strategy: :one_for_one) end - end From 5f31dcf58680ec69120caf0192750a02d71d61c5 Mon Sep 17 00:00:00 2001 From: Zack Kollar Date: Fri, 23 Feb 2024 23:38:21 -0500 Subject: [PATCH 4/6] :octopus: mix format --- lib/que.ex | 12 ++------ lib/que/helpers.ex | 16 +++-------- lib/que/job.ex | 53 +++++++++++------------------------- lib/que/server_supervisor.ex | 29 ++++---------------- 4 files changed, 28 insertions(+), 82 deletions(-) diff --git a/lib/que.ex b/lib/que.ex index 3f8c93d..87b5eb5 100644 --- a/lib/que.ex +++ b/lib/que.ex @@ -17,7 +17,7 @@ defmodule Que do ``` defp deps do - [{:que, "~> #{Que.Mixfile.project[:version]}"}] + [{:que, "~> #{Que.Mixfile.project()[:version]}"}] end ``` @@ -80,20 +80,14 @@ defmodule Que do """ - - - @doc """ Starts the Que Application (and its Supervision Tree) """ def start(_type, _args) do Que.Helpers.log("Booting Que", :low) - Que.Supervisor.start_link + Que.Supervisor.start_link() end - - - @doc """ Enqueues a Job to be processed by Que. @@ -112,6 +106,4 @@ defmodule Que do """ @spec add(worker :: module, arguments :: term) :: {:ok, %Que.Job{}} defdelegate add(worker, arguments), to: Que.ServerSupervisor - end - diff --git a/lib/que/helpers.ex b/lib/que/helpers.ex index 2d3e9c6..13a883a 100644 --- a/lib/que/helpers.ex +++ b/lib/que/helpers.ex @@ -5,43 +5,35 @@ defmodule Que.Helpers do @moduledoc false @log_levels [low: 0, medium: 1, high: 2] - @min_level Application.get_env(:que, :log_level, :low) - + @min_level Application.compile_env(:que, :log_level, :low) ## Helper Module for `Que`. Exports methods that are used in the ## project internally. Not meant to be used as part of the Public ## API. - - @doc """ Logger wrapper for internal Que use. Doesn't log messages if the specified level is `:low` and the enviroment is `:test`. """ - @spec log(message :: String.t, level :: atom) :: :ok + @spec log(message :: String.t(), level :: atom) :: :ok def log(message, level \\ :medium) do - if (level_value(level) >= level_value(@min_level)) do + if level_value(level) >= level_value(@min_level) do Logger.info("#{@prefix} #{message}") end end - - @doc """ Off-loads tasks to custom `Que.TaskSupervisor` """ - @spec do_task((() -> any)) :: {:ok, pid} + @spec do_task((-> any)) :: {:ok, pid} def do_task(fun) do Task.Supervisor.start_child(Que.TaskSupervisor, fun) end - - # Convert Log Level to Integer defp level_value(level) when is_atom(level) do @log_levels[level] || 0 end - end diff --git a/lib/que/job.ex b/lib/que/job.ex index d8b97dc..f99a787 100644 --- a/lib/que/job.ex +++ b/lib/que/job.ex @@ -1,10 +1,9 @@ defmodule Que.Job do require Logger - defstruct [:id, :arguments, :worker, :status, :ref, :pid, :created_at, :updated_at] + defstruct [:id, :arguments, :worker, :status, :ref, :pid, :created_at, :updated_at] ## Note: Update Que.Persistence.Mnesia after changing these values - @moduledoc """ Module to manage a Job's state and execute the worker's callbacks. @@ -13,49 +12,39 @@ defmodule Que.Job do unless you absolutely know what you're doing. """ - @statuses [:queued, :started, :failed, :completed] - @typedoc "One of the atoms in `#{inspect(@statuses)}`" - @type status :: atom - - @typedoc "A `Que.Job` struct" - @type t :: %Que.Job{} - - + @typedoc "One of the atoms in `#{inspect(@statuses)}`" + @type status :: atom + @typedoc "A `Que.Job` struct" + @type t :: %Que.Job{} @doc """ Returns a new Job struct with defaults """ - @spec new(worker :: Que.Worker.t, args :: list) :: Que.Job.t + @spec new(worker :: Que.Worker.t(), args :: list) :: Que.Job.t() def new(worker, args \\ nil) do %Que.Job{ - status: :queued, - worker: worker, + status: :queued, + worker: worker, arguments: args } end - - - @doc """ Update the Job status to one of the predefined values in `@statuses` """ - @spec set_status(job :: Que.Job.t, status :: status) :: Que.Job.t + @spec set_status(job :: Que.Job.t(), status :: status) :: Que.Job.t() def set_status(job, status) when status in @statuses do - %{ job | status: status } + %{job | status: status} end - - - @doc """ Updates the Job struct with new status and spawns & monitors a new Task under the TaskSupervisor which executes the perform method with supplied arguments """ - @spec perform(job :: Que.Job.t) :: Que.Job.t + @spec perform(job :: Que.Job.t()) :: Que.Job.t() def perform(job) do Que.Helpers.log("Starting #{job}") @@ -66,17 +55,14 @@ defmodule Que.Job do job.worker.perform(job.arguments) end) - %{ job | status: :started, pid: pid, ref: Process.monitor(pid) } + %{job | status: :started, pid: pid, ref: Process.monitor(pid)} end - - - @doc """ Handles Job Success, Calls appropriate worker method and updates the job status to :completed """ - @spec handle_success(job :: Que.Job.t) :: Que.Job.t + @spec handle_success(job :: Que.Job.t()) :: Que.Job.t() def handle_success(job) do Que.Helpers.log("Completed #{job}") @@ -86,17 +72,14 @@ defmodule Que.Job do job.worker.on_teardown(job) end) - %{ job | status: :completed, pid: nil, ref: nil } + %{job | status: :completed, pid: nil, ref: nil} end - - - @doc """ Handles Job Failure, Calls appropriate worker method and updates the job status to :failed """ - @spec handle_failure(job :: Que.Job.t, error :: term) :: Que.Job.t + @spec handle_failure(job :: Que.Job.t(), error :: term) :: Que.Job.t() def handle_failure(job, error) do Que.Helpers.log("Failed #{job}") @@ -106,13 +89,10 @@ defmodule Que.Job do job.worker.on_teardown(job) end) - %{ job | status: :failed, pid: nil, ref: nil } + %{job | status: :failed, pid: nil, ref: nil} end end - - - ## Implementing the String.Chars protocol for Que.Job structs defimpl String.Chars, for: Que.Job do @@ -120,4 +100,3 @@ defimpl String.Chars, for: Que.Job do "Job # #{job.id} with #{ExUtils.Module.name(job.worker)}" end end - diff --git a/lib/que/server_supervisor.ex b/lib/que/server_supervisor.ex index e405897..7d0b318 100644 --- a/lib/que/server_supervisor.ex +++ b/lib/que/server_supervisor.ex @@ -9,14 +9,11 @@ defmodule Que.ServerSupervisor do you absolutely know what you're doing. """ - - - @doc """ Starts the Supervision Tree """ - @spec start_link() :: Supervisor.on_start - def start_link do + @spec start_link(:ok) :: Supervisor.on_start() + def start_link(_) do Que.Helpers.log("Booting Server Supervisor for Workers", :low) pid = Supervisor.start_link(@module, :ok, name: @module) @@ -25,21 +22,15 @@ defmodule Que.ServerSupervisor do pid end - - - @doc """ Starts a `Que.Server` for the given worker """ - @spec start_server(worker :: Que.Worker.t) :: Supervisor.on_start_child | no_return + @spec start_server(worker :: Que.Worker.t()) :: Supervisor.on_start_child() | no_return def start_server(worker) do Que.Worker.validate!(worker) Supervisor.start_child(@module, [worker]) end - - - # If the server for the worker is running, add job to it. # If not, spawn a new server first and then add it. @doc false @@ -51,9 +42,6 @@ defmodule Que.ServerSupervisor do Que.Server.add(worker, args) end - - - @doc false def init(:ok) do children = [ @@ -63,15 +51,12 @@ defmodule Que.ServerSupervisor do supervise(children, strategy: :simple_one_for_one) end - - - # Spawn all (valid) Workers with queued jobs defp resume_queued_jobs do {valid, invalid} = - Que.Persistence.incomplete - |> Enum.map(&(&1.worker)) - |> Enum.uniq + Que.Persistence.incomplete() + |> Enum.map(& &1.worker) + |> Enum.uniq() |> Enum.split_with(&Que.Worker.valid?/1) # Notify user about pending jobs for Invalid Workers @@ -85,6 +70,4 @@ defmodule Que.ServerSupervisor do Enum.map(valid, &start_server/1) end end - end - From 8cf85d216e75eeb6b9e04f95e517925f997ca3b0 Mon Sep 17 00:00:00 2001 From: Zack Kollar Date: Sat, 24 Feb 2024 00:12:23 -0500 Subject: [PATCH 5/6] :hammer: Replace deprecated :simple_one_for_one Supervisor with DynamicSupervisor --- lib/que/server_supervisor.ex | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/que/server_supervisor.ex b/lib/que/server_supervisor.ex index 7d0b318..2e8a29d 100644 --- a/lib/que/server_supervisor.ex +++ b/lib/que/server_supervisor.ex @@ -1,5 +1,5 @@ defmodule Que.ServerSupervisor do - use Supervisor + use DynamicSupervisor @module __MODULE__ @@ -15,10 +15,11 @@ defmodule Que.ServerSupervisor do @spec start_link(:ok) :: Supervisor.on_start() def start_link(_) do Que.Helpers.log("Booting Server Supervisor for Workers", :low) - pid = Supervisor.start_link(@module, :ok, name: @module) + pid = DynamicSupervisor.start_link(@module, :ok, name: @module) # Resume Pending Jobs resume_queued_jobs() + pid end @@ -28,7 +29,7 @@ defmodule Que.ServerSupervisor do @spec start_server(worker :: Que.Worker.t()) :: Supervisor.on_start_child() | no_return def start_server(worker) do Que.Worker.validate!(worker) - Supervisor.start_child(@module, [worker]) + DynamicSupervisor.start_child(@module, {Que.Server, worker}) end # If the server for the worker is running, add job to it. @@ -44,11 +45,7 @@ defmodule Que.ServerSupervisor do @doc false def init(:ok) do - children = [ - worker(Que.Server, []) - ] - - supervise(children, strategy: :simple_one_for_one) + DynamicSupervisor.init(strategy: :one_for_one) end # Spawn all (valid) Workers with queued jobs From c0f67519f0421e9be55dc4074a5a755492263d4f Mon Sep 17 00:00:00 2001 From: Zack Kollar Date: Sat, 24 Feb 2024 00:25:30 -0500 Subject: [PATCH 6/6] :books: Bump version to 0.11.0 --- CHANGELOG.md | 5 +++++ README.md | 2 +- mix.exs | 3 +-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7a423..d9ba5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Changelog ========= +## Version 0.11.0 + +- [Enhancement] Update to Erlang/OTP 26 and Elixir 1.16, remove deprecated warnings + + ## Version 0.10.1 diff --git a/README.md b/README.md index d94920c..4afa938 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Add `que` to your project dependencies in `mix.exs`: ```elixir def deps do - [{:que, "~> 0.10.1"}] + [{:que, "~> 0.11.0"}] end ``` diff --git a/mix.exs b/mix.exs index 18de86a..85f7e53 100644 --- a/mix.exs +++ b/mix.exs @@ -3,7 +3,7 @@ defmodule Que.Mixfile do @app :que @name "Que" - @version "0.10.1" + @version "0.11.0" @github "https://github.com/sheharyarn/#{@app}" @@ -78,4 +78,3 @@ defmodule Que.Mixfile do ] end end -