towerops/vendor/oban_pro/lib/oban/pro/queue.ex
Graham McIntire 6c05d45dd6 deps: upgrade oban_pro to 1.7.0
Bumps vendored Oban Pro from 1.6.13 to 1.7.0, which transitively bumps
oban core to 2.22.1 (requires migrations v14) and db_connection to 2.10.0.

- mix.exs constraint: ~> 1.6 → ~> 1.7
- vendor/oban_pro/ replaced with v1.7.0 hex package
- migration 20260430142200: Oban core v12 → v14 (must run first)
- migration 20260430142241: Oban Pro 1.7.0 schema additions

Also corrects a pre-existing constraint name in AgentAssignment that was
left stale by the equipment→devices rename migration (20260117190134).
The unique index is named agent_assignments_device_id_index, but the
schema's unique_constraint/3 still pointed at the old equipment_id name,
causing the test suite to surface Ecto.ConstraintError instead of a
changeset error. Required to get the suite green for this upgrade.
2026-04-30 10:26:18 -05:00

161 lines
4.4 KiB
Elixir

defmodule Oban.Pro.Queue do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
alias Oban.Pro.{Producer, Utils}
@allowed ~w(ack_async local_limit paused refresh_interval)a
@primary_key {:name, :string, autogenerate: false}
schema "oban_queues" do
field :lock_version, :integer, default: 1
field :hash, :string
embeds_one :only, Only, on_replace: :update, primary_key: false do
@moduledoc false
field :mode, Ecto.Enum, values: [:node, :sys_env]
field :op, Ecto.Enum, values: [:==, :!=, :=~]
field :key, :string
field :value, :string
end
embeds_one :opts, Opts, on_replace: :update, primary_key: false do
@moduledoc false
field :ack_async, :boolean
field :local_limit, :integer
field :paused, :boolean
field :refresh_interval, :integer
field :xact_delay, :integer
field :xact_retry, :integer
embeds_one :global_limit, GlobalLimit, on_replace: :update, primary_key: false do
@moduledoc false
field :allowed, :integer
field :burst, :boolean, default: false
embeds_one :partition, Partition, on_replace: :update, primary_key: false do
@moduledoc false
field :fields, {:array, Ecto.Enum}, values: [:args, :meta, :worker]
field :keys, {:array, :string}
end
end
embeds_one :rate_limit, RateLimit, on_replace: :update, primary_key: false do
@moduledoc false
field :algorithm, Ecto.Enum,
values: ~w(sliding_window fixed_window token_bucket)a,
default: :sliding_window
field :allowed, :integer
field :period, :integer
field :window_time, :integer, virtual: true, skip_default_validation: true
embeds_one :partition, Partition, on_replace: :update, primary_key: false do
@moduledoc false
field :fields, {:array, Ecto.Enum}, values: [:args, :meta, :worker]
field :keys, {:array, :string}
end
end
end
timestamps(inserted_at: :inserted_at, updated_at: :updated_at, type: :utc_datetime_usec)
end
def normalize(params) do
case params do
[_ | _] -> Map.new(params)
{name, [_ | _] = opts} -> %{name: name, opts: Map.new(opts)}
{name, limit} -> %{name: name, opts: %{local_limit: limit}}
end
end
def changeset(params) do
changeset(%__MODULE__{}, normalize(params))
end
def changeset(schema, params) do
params =
params
|> Map.replace_lazy(:name, fn _ -> to_string(params[:name]) end)
|> extract_only()
schema
|> cast(params, [:name])
|> cast_embed(:only, with: &only_changeset/2)
|> cast_embed(:opts, required: true, with: &opts_changeset/2)
|> validate_required([:name])
|> validate_length(:name, min: 1)
|> optimistic_lock(:lock_version)
|> inject_hash(params)
|> Utils.enforce_keys(params, __MODULE__)
end
defp extract_only(params) do
case params do
%{opts: %{only: _}} ->
{only, params} = pop_in(params, [:opts, :only])
Map.put(params, :only, cast_only(only))
_ ->
params
end
end
defp only_changeset(schema, params) do
schema
|> cast(params, ~w(mode op key value)a)
|> validate_required(~w(mode op value)a)
|> Utils.enforce_keys(params, __MODULE__.Only)
end
defp opts_changeset(schema, params) do
params = Map.new(params, fn {key, val} -> {Utils.maybe_to_atom(key), val} end)
Producer.meta_changeset(schema, params, @allowed)
end
defp inject_hash(changeset, params) do
hash =
params
|> Map.take(~w(only opts)a)
|> Enum.map_join(&:erlang.phash2/1)
|> Utils.hash64()
put_change(changeset, :hash, hash)
end
@spec to_keyword_opts(%{opts: map()} | map()) :: Keyword.t()
def to_keyword_opts(%__MODULE__{name: queue, opts: opts}) do
opts
|> Ecto.embedded_dump(:json)
|> Map.put(:queue, queue)
|> to_keyword_opts()
end
def to_keyword_opts(opts) do
for {key, val} <- opts, not is_nil(val), do: {Utils.maybe_to_atom(key), val}
end
# Helpers
defp cast_only({:node, value}), do: cast_only({:node, :==, value})
defp cast_only({:node, op, value}), do: %{mode: :node, op: op, value: to_string(value)}
defp cast_only({:sys_env, key, value}), do: cast_only({:sys_env, key, :==, value})
defp cast_only({:sys_env, key, op, value}) do
%{mode: :sys_env, op: op, key: key, value: to_string(value)}
end
defp cast_only(other), do: other
end