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.
161 lines
4.4 KiB
Elixir
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
|