chore: update dependencies. phoenix 1.8.8→1.8.9, swoosh 1.26.2→1.26.3, oban_pro 1.7.6→1.7.7, oban_web 2.12.5→2.12.6, hackney 4.4.5→4.5.2, plus transitive deps
This commit is contained in:
parent
bdb0dd8c38
commit
a719135c1e
31 changed files with 402 additions and 431 deletions
24
mix.lock
24
mix.lock
|
|
@ -11,11 +11,11 @@
|
|||
"cloak": {:hex, :cloak, "1.1.4", "aba387b22ea4d80d92d38ab1890cc528b06e0e7ef2a4581d71c3fdad59e997e7", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "92b20527b9aba3d939fab0dd32ce592ff86361547cfdc87d74edce6f980eb3d7"},
|
||||
"cloak_ecto": {:hex, :cloak_ecto, "1.3.0", "0de127c857d7452ba3c3367f53fb814b0410ff9c680a8d20fbe8b9a3c57a1118", [:mix], [{:cloak, "~> 1.1.1", [hex: :cloak, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "314beb0c123b8a800418ca1d51065b27ba3b15f085977e65c0f7b2adab2de1cc"},
|
||||
"comeonin": {:hex, :comeonin, "5.5.1", "5113e5f3800799787de08a6e0db307133850e635d34e9fab23c70b6501669510", [:mix], [], "hexpm", "65aac8f19938145377cee73973f192c5645873dcf550a8a6b18187d17c13ccdb"},
|
||||
"cowboy": {:hex, :cowboy, "2.16.1", "fa04080b602ff25c40a7700f2dc0152dbc1ba26b42093ae0fa9bb7a337d5a242", [:make, :rebar3], [{:cowlib, ">= 2.16.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "b8ea4dd317a043e3177ec840cfa3bcb47cfb41035d3abb24d954dc7d51def399"},
|
||||
"cowboy": {:hex, :cowboy, "2.17.0", "059d6ae769214cedf55d115ce5bf38649ff6b32ec693067cf6b185d0ab1b53c3", [:make, :rebar3], [{:cowlib, ">= 2.18.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "84f0e4c9d5820342cd506472052b79336d0d9d3624e46303f6d0af9dc94e8d5f"},
|
||||
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
||||
"cowlib": {:hex, :cowlib, "2.17.1", "3e6053016d1ab245730f0af688755476dcedb1c25ed8fb5751f59a2bfdc0c9af", [:make, :rebar3], [], "hexpm", "ff08bd17e6dd931445b18af77315b9b5fe052407110964ad2588c686b57b5e3f"},
|
||||
"cowlib": {:hex, :cowlib, "2.18.0", "4a3ef8cb012c21c7cbb7c925f75405e26d7fcd393fd78c46187539dbc9a48310", [:make, :rebar3], [], "hexpm", "c4f89d33a61162d4cfdcb5a1af7e562d80a700b2573cc71020ce6521b152dc1a"},
|
||||
"credo": {:hex, :credo, "1.7.19", "cc52129665fc7c15143d47838fda0f9cd6dac9ceced7bf4da6f85fcbfe64b12a", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2d8bc95d5a7bb99dd2613621d4f08c6a3575c3fd4b62e6a2b48a100352a557b8"},
|
||||
"db_connection": {:hex, :db_connection, "2.10.1", "d5465f6bcc125c1b8981c1dbf23c193ca16f446ec0b25832dc174f74f18be510", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "18ed94c6e627b4bf452dbd4df61b69a35a1e768525140bc1917b7a685026a6a3"},
|
||||
"db_connection": {:hex, :db_connection, "2.10.2", "ae391e803a5adff104da913c2fc1c0c14a37f8b10001dcef568796e1fb7bf95c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "510b14482330f1af6490a2fa0efd8d4f1435d1529b165647df22ac0f2df0fa93"},
|
||||
"decimal": {:hex, :decimal, "3.1.1", "430d87b04011ce6cbd4fd205be758311a81f87d552d40904abd00f015935b1d0", [:mix], [], "hexpm", "c5f25f2ced74a0587d03e6023f595db8e924c9d3922c8c8ffd9edfc4498cf1f6"},
|
||||
"dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"},
|
||||
"dns_cluster": {:hex, :dns_cluster, "0.2.0", "aa8eb46e3bd0326bd67b84790c561733b25c5ba2fe3c7e36f28e88f384ebcb33", [:mix], [], "hexpm", "ba6f1893411c69c01b9e8e8f772062535a4cf70f3f35bcc964a324078d8c8240"},
|
||||
|
|
@ -36,10 +36,10 @@
|
|||
"geo": {:hex, :geo, "4.1.0", "64ba89a64cc400b5b16dd2f5bd644cb141776eb8c2ac5a983332c8d944936c12", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "19edb2b3398ca9f701b573b1fb11bc90951ebd64f18b06bd1bf35abe509a2934"},
|
||||
"geo_postgis": {:hex, :geo_postgis, "3.7.1", "614f25b42334a615bd54bb09c22030b1aac7bac8f829bd823ab1faccf093a324", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:geo, "~> 3.6 or ~> 4.0", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "c20d823c600d35b7fe9ddd5be03052bb7136c57d6f1775dbd46871545e405280"},
|
||||
"gettext": {:hex, :gettext, "1.0.2", "5457e1fd3f4abe47b0e13ff85086aabae760497a3497909b8473e0acee57673b", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "eab805501886802071ad290714515c8c4a17196ea76e5afc9d06ca85fb1bfeb3"},
|
||||
"h2": {:hex, :h2, "0.10.2", "ea0146b9c8b5f3b5de16045765f5684db38ef1e66f1c60444890948cb1003e47", [:rebar3], [], "hexpm", "497a899f338b42e6a0b292524e635b0ce6f9379fa39395c8e38d06351cd9b9cf"},
|
||||
"hackney": {:hex, :hackney, "4.4.5", "a908f620525bb886a16613532324762e5166287f8c00c9888a762edee11a30c0", [:rebar3], [{:certifi, "~> 2.17.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:h2, "~> 0.10.1", [hex: :h2, repo: "hexpm", optional: false]}, {:idna, "~> 7.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.2", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:quic, "~> 1.6.5", [hex: :quic, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:webtransport, "~> 0.4.1", [hex: :webtransport, repo: "hexpm", optional: false]}], "hexpm", "6d72bef4e135e94c522c271e11fbb6933efb0006ef235a3933807d0be73b71ec"},
|
||||
"h2": {:hex, :h2, "0.10.4", "31ef580056e19977b6542eea2718aa19a45841205cd82cd48535dd7683caea4c", [:rebar3], [], "hexpm", "8350920ac7c259fb759a2830d3ce0dd248c48422a031d1760bebdd2020fa30a9"},
|
||||
"hackney": {:hex, :hackney, "4.5.2", "d44b00b6e91ef8c480ec51ad42e9d8777a3a391ea78865cb16c5c0645399c6f5", [:rebar3], [{:certifi, "~> 2.17.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:h2, "~> 0.10.4", [hex: :h2, repo: "hexpm", optional: false]}, {:idna, "~> 7.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.2", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:quic, "~> 1.7.0", [hex: :quic, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:webtransport, "~> 0.4.3", [hex: :webtransport, repo: "hexpm", optional: false]}], "hexpm", "5db2e2d7de05cafcd681e21120ae4c8b5a378ebeb9b8d8835f26f456a9a80f7a"},
|
||||
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]},
|
||||
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
|
||||
"hpax": {:hex, :hpax, "1.0.4", "777de5d433b0fbdc7c418159c8055910faa8047ffdb3d6b31098d2a46cd7685c", [:mix], [], "hexpm", "afc7cb142ebcc2d01ce7816190b98ce5dd49e799111b24249f3443d730f377ca"},
|
||||
"httpoison": {:hex, :httpoison, "3.0.0", "8566a933bb9175236d1ec335978445b67cd1f5b5d3ead6ca4b80be469d41f5d9", [:mix], [{:hackney, "~> 4.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "9130197b7658901c493d6fcfb842fb9676300fa8a6c8ed058c8889cf1a77f3c2"},
|
||||
"idna": {:hex, :idna, "7.1.0", "1067a13043538129602d2f2ce6899d8713125c7d19734aa557ce2e3ea55bd4f1", [:rebar3], [], "hexpm", "6ae959a025bf36df61a8cab8508d9654891b5426a84c44d82deaffd6ddf8c71f"},
|
||||
"inet_cidr": {:hex, :inet_cidr, "1.0.9", "e0ef72a2942529da78c8e4147d53f2ef5f6f5293335c3637b0fdf83c012cc816", [:mix], [], "hexpm", "172da15ff7cf635b1feaf14f5818be28c811b37cc5fb7c5f7c01058c1c1066cc"},
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
"logger_file_backend": {:hex, :logger_file_backend, "0.0.14", "774bb661f1c3fed51b624d2859180c01e386eb1273dc22de4f4a155ef749a602", [:mix], [], "hexpm", "071354a18196468f3904ef09413af20971d55164267427f6257b52cfba03f9e6"},
|
||||
"mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"},
|
||||
"mimerl": {:hex, :mimerl, "1.5.0", "f35aca6f23242339b3666e0ac0702379e362b469d0aea167f6cc713547e777ed", [:rebar3], [], "hexpm", "db648ce065bae14ea84ca8b5dd123f42f49417cef693541110bf6f9e9be9ecc4"},
|
||||
"mint": {:hex, :mint, "1.9.0", "d6f534c2a3e98b2a8cc749b4796eb77e9e3af79a76f96e4c74035a827de0d318", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "007154c7d8c43916aed3c93afd1f11aebbaa9c5ff4b7ba55ebe0d17ee0296042"},
|
||||
"mint": {:hex, :mint, "1.9.1", "3bc120b743ed2e99ad920910f2613e9faebabb2257731b0e2ea4d8ccd9eceede", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "831101bd560b086316fab5f7adb21a4f3455717d8e4bc8368b052e09aa9163e0"},
|
||||
"mix_audit": {:hex, :mix_audit, "2.1.5", "c0f77cee6b4ef9d97e37772359a187a166c7a1e0e08b50edf5bf6959dfe5a016", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "87f9298e21da32f697af535475860dc1d3617a010e0b418d2ec6142bc8b42d69"},
|
||||
"mix_test_watch": {:hex, :mix_test_watch, "1.4.0", "d88bcc4fbe3198871266e9d2f00cd8ae350938efbb11d3fa1da091586345adbb", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "2b4693e17c8ead2ef56d4f48a0329891e8c2d0d73752c0f09272a2b17dc38d1b"},
|
||||
"mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"},
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
"octo_fetch": {:hex, :octo_fetch, "0.5.0", "f50701568b9fc752656367f82cc134d5fbefff37c5a0e8ddfcceb02ceee3f5fc", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "6226cc3c14ca948ee9f25fb0446322e5c288e215da9beba7899b6b5f4cd3ccb0"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.4.2", "c352ddc1a0d5e54f9b1654d45f9c432eef76f9cea371c55ddff769ef688fdb74", [:rebar3], [], "hexpm", "4c25347de3b7c35732d32e69ab43d1ceee0beae3f3b3ade1b59cbd3dd224d9ca"},
|
||||
"peep": {:hex, :peep, "4.4.0", "4b6289e7258ecf2741041068932455eb8389673bca785623621ddb6935286845", [:mix], [{:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:plug, "~> 1.16", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f289959a9e5fcf92f5a4becaf4dd0df95c58841368f6ad0574b8ea830a7c1453"},
|
||||
"phoenix": {:hex, :phoenix, "1.8.8", "ada3d761359274178180c0e992ef0c2b536bd7c3bd75ebba94acbf39ab4347fe", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "f0c843037bd2e7012fc1d1ec9574dfa6972b7e3d09e9b77fd23aa283af0aa994"},
|
||||
"phoenix": {:hex, :phoenix, "1.8.9", "a63ed0962ed5b903b146dab0ae8eb8387fe478f8171a5e26d56a165f35996fe1", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "3477e2dd5a4f61820341169031bdfe21275f659923bea9c5c0ea2aa1c3fcc046"},
|
||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.7.0", "75c4b9dfb3efdc42aec2bd5f8bccd978aca0651dbcbc7a3f362ea5d9d43153c6", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "1d75011e4254cb4ddf823e81823a9629559a1be93b4321a6a5f11a5306fbf4cc"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "4.3.0", "d3577a5df4b6954cd7890c84d955c470b5310bb49647f0a114a6eeecc850f7ad", [:mix], [], "hexpm", "3eaa290a78bab0f075f791a46a981bbe769d94bc776869f4f3063a14f30497ad"},
|
||||
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.7", "405880012cb4b706f26dd1c6349125bfc903fb9e44d1ea668adaf4e04d4884b7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "3a8625cab39ec261d48a13b7468dc619c0ede099601b084e343968309bd4d7d7"},
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
||||
"postgrex": {:hex, :postgrex, "0.22.2", "4aec14df2a72722aee92492566edbeeb44e233ecb86b1915d03136297ef1385d", [:mix], [{:db_connection, "~> 2.9", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8946382ddb06294f56026ac4278b3cc212bac8a2c82ed68b4087819ed1abc53b"},
|
||||
"prom_ex": {:hex, :prom_ex, "1.12.0", "a82cbd5b49964e4d4295ab72a18e007aadd5f4a91630b7c49fad42cc7e49c880", [:mix], [{:absinthe, ">= 1.8.0", [hex: :absinthe, repo: "hexpm", optional: true]}, {:broadway, ">= 1.1.0", [hex: :broadway, repo: "hexpm", optional: true]}, {:ecto, ">= 3.14.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:finch, "~> 0.18", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, ">= 2.10.0", [hex: :oban, repo: "hexpm", optional: true]}, {:octo_fetch, "~> 0.4", [hex: :octo_fetch, repo: "hexpm", optional: false]}, {:peep, "~> 3.0 or ~> 4.0", [hex: :peep, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.7.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, ">= 0.20.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, ">= 1.16.0", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 2.6.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, ">= 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.2", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 1.1", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "6357484941489ba2fee64bb1e9f2a1e86309545304f9e90144e3c10e553c958b"},
|
||||
"quic": {:hex, :quic, "1.6.5", "28b7d49c1732b2de3861701bb03ae7798537240552370ac49f0d139d2ea8f621", [:rebar3], [], "hexpm", "de1a88972c33201a50d1a17c8c4a14528bd1d8f25ef705897d680ae312d0aa78"},
|
||||
"quic": {:hex, :quic, "1.7.0", "ebcf105fb16ca4d954c3bbd2e5bcda7650074f3e3a9ca80135dbee2607e0c27e", [:rebar3], [], "hexpm", "d0d304e5fda48754a570b90b103153f780f9926c15f6eabfe1b343e4f61e32df"},
|
||||
"ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"},
|
||||
"redix": {:hex, :redix, "1.5.3", "4eaae29c75e3285c0ff9957046b7c209aa7f72a023a17f0a9ea51c2a50ab5b0f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:nimble_options, "~> 0.5.0 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7b06fb5246373af41f5826b03334dfa3f636347d4d5d98b4d455b699d425ae7e"},
|
||||
"req": {:hex, :req, "0.6.2", "b9b2024f35bcf60a92cc8cad2eaaf9d4e7aace463ff74be1afe5986830184413", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.21", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cc9cd30a2ddd04989929b887178e1610c940456d962c6c3a52df6146d2eef9bf"},
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
"stream_data": {:hex, :stream_data, "1.3.0", "bde37905530aff386dea1ddd86ecbf00e6642dc074ceffc10b7d4e41dfd6aac9", [:mix], [], "hexpm", "3cc552e286e817dca43c98044c706eec9318083a1480c52ae2688b08e2936e3c"},
|
||||
"styler": {:hex, :styler, "1.11.0", "35010d970689a23c2bcc8e97bd8bf7d20e3561d60c49be84654df5c37d051a9c", [:mix], [], "hexpm", "70f36165d0cf238a32b7a456fdef6a9c72e77e657d7ac4a0ace33aeba3f2b8c0"},
|
||||
"sweet_xml": {:hex, :sweet_xml, "0.7.5", "803a563113981aaac202a1dbd39771562d0ad31004ddbfc9b5090bdcd5605277", [:mix], [], "hexpm", "193b28a9b12891cae351d81a0cead165ffe67df1b73fe5866d10629f4faefb12"},
|
||||
"swoosh": {:hex, :swoosh, "1.26.2", "1e5f398c6ab313d028b9bf604165f051e279093090c50b6f93090cf6a599b0f7", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, ">= 1.9.0 and < 5.0.0", [hex: :hackney, repo: "hexpm", optional: true]}, {:idna, ">= 6.0.0 and < 8.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "08c6a1636b82721d0f64259053a733526526d077011ff6a7776f80e21dc60757"},
|
||||
"swoosh": {:hex, :swoosh, "1.26.3", "9d8b60077305ce259298d9a1102e5be67cd3c41d1ea930c29e9288af195ca017", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, ">= 1.9.0 and < 5.0.0", [hex: :hackney, repo: "hexpm", optional: true]}, {:idna, ">= 6.0.0 and < 8.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c7683d070fe8f8aa9d174e61b01f2d527be73cd8ac40037b7109184941eb569f"},
|
||||
"table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},
|
||||
"tailwind": {:hex, :tailwind, "0.5.1", "35435b13158c90d37da11e1cfc808755fca1d7b6c5ab87b1b19c5de87e2f0a10", [:mix], [], "hexpm", "c4e26302a59fec72abc5610ecb6ad2116d9aa31f31aab2d4b8eb6e95d25a689c"},
|
||||
"telemetry": {:hex, :telemetry, "1.4.2", "a0cb522801dffb1c49fe6e30561badffc7b6d0e180db1300df759faa22062855", [:rebar3], [], "hexpm", "928f6495066506077862c0d1646609eed891a4326bee3126ba54b60af61febb1"},
|
||||
|
|
@ -100,8 +100,8 @@
|
|||
"thousand_island": {:hex, :thousand_island, "1.5.0", "f50a213cac97262b6d5ebb85745aa2c00fec1413191e6e66834788d45425cecb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "708923d40523e43cf99041ab37a0d4b0ec426ac6438fa3716ab23d919eaeb412"},
|
||||
"tzdata": {:hex, :tzdata, "1.1.4", "989e0855df5ee8c40eb929ad971bedd7a51e2c223f051fd95cc2d2cf56a60c19", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "ab48888699de8ff4a255522fd858abe81bac2e64690a375e6cb590112cf4a24e"},
|
||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.5.9", "43dc3ba6d89ef5dec5b1d0a39698436a1e856d000d84bf31a3149862b01a287f", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5534d5c9adad3c18a0f58a9371220d75a803bf0b9a3d87e6fe072faaeed76a08"},
|
||||
"webtransport": {:hex, :webtransport, "0.4.1", "60ef6cd99282b5964c8172d674519239e31e357d934bde028bec70da34636fe5", [:rebar3], [{:h2, "~> 0.10.1", [hex: :h2, repo: "hexpm", optional: false]}, {:quic, "~> 1.6.5", [hex: :quic, repo: "hexpm", optional: false]}], "hexpm", "006e4e52a8f03b69201d4637c85b424a4ddccc1909f32c5742fed8d495a75174"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.6.0", "73db5ab8aaefd1a876a97ce3e6afc96562625de69ef17a4e04426e034849d0b8", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "50021a85bce8f203b086705d9e0c5415e2c7eb05d319111b0428fe71f9934617"},
|
||||
"webtransport": {:hex, :webtransport, "0.4.3", "df0c53da138cdc5f3390a31ef612caa3a041c23e18c1a0b6fbd4d72743277806", [:rebar3], [{:h2, "~> 0.10.4", [hex: :h2, repo: "hexpm", optional: false]}, {:quic, "~> 1.7.0", [hex: :quic, repo: "hexpm", optional: false]}], "hexpm", "3ae8c76696cdb56bee3caf1dd853a0a596339886468ca17c578a9bfd647dab9d"},
|
||||
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
|
||||
"yaml_elixir": {:hex, :yaml_elixir, "2.12.2", "9dd1330fb4cd9a36a7b0f502e5b12486eff632792ee4a5f0eba52a4d4ec32c9c", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "e7c1b10122f973e6558462d51c39026ba0e14afbc6745318e990ea82cfe9e159"},
|
||||
}
|
||||
|
|
|
|||
BIN
vendor/oban_pro/.hex
vendored
BIN
vendor/oban_pro/.hex
vendored
Binary file not shown.
80
vendor/oban_pro/hex_metadata.config
vendored
80
vendor/oban_pro/hex_metadata.config
vendored
|
|
@ -1,80 +0,0 @@
|
|||
{<<"links">>,[]}.
|
||||
{<<"name">>,<<"oban_pro">>}.
|
||||
{<<"version">>,<<"1.7.6">>}.
|
||||
{<<"description">>,<<"Oban Pro Component">>}.
|
||||
{<<"elixir">>,<<"~> 1.15">>}.
|
||||
{<<"files">>,
|
||||
[<<"lib/oban">>,<<"lib/oban/pro">>,<<"lib/oban/pro/diagnostics.ex">>,
|
||||
<<"lib/oban/pro/cron.ex">>,<<"lib/oban/pro/decorator.ex">>,
|
||||
<<"lib/oban/pro/migrations">>,<<"lib/oban/pro/migrations/v1_4_0.ex">>,
|
||||
<<"lib/oban/pro/migrations/v1_5_0.ex">>,
|
||||
<<"lib/oban/pro/migrations/v1_6_0.ex">>,
|
||||
<<"lib/oban/pro/migrations/v1_7_0.ex">>,
|
||||
<<"lib/oban/pro/migrations/dynamic_partitioner.ex">>,
|
||||
<<"lib/oban/pro/migrations/v1_0_0.ex">>,<<"lib/oban/pro/unique.ex">>,
|
||||
<<"lib/oban/pro/batch.ex">>,<<"lib/oban/pro/chunk.ex">>,
|
||||
<<"lib/oban/pro/producer.ex">>,<<"lib/oban/pro/worker.ex">>,
|
||||
<<"lib/oban/pro/stages">>,<<"lib/oban/pro/stages/rate.ex">>,
|
||||
<<"lib/oban/pro/stages/chain.ex">>,<<"lib/oban/pro/stages/encrypted.ex">>,
|
||||
<<"lib/oban/pro/stages/recorded.ex">>,<<"lib/oban/pro/stages/hooks.ex">>,
|
||||
<<"lib/oban/pro/stages/deadline.ex">>,
|
||||
<<"lib/oban/pro/stages/executing.ex">>,
|
||||
<<"lib/oban/pro/stages/structured.ex">>,<<"lib/oban/pro/plugins">>,
|
||||
<<"lib/oban/pro/plugins/dynamic_prioritizer.ex">>,
|
||||
<<"lib/oban/pro/plugins/dynamic_pruner.ex">>,
|
||||
<<"lib/oban/pro/plugins/dynamic_scaler.ex">>,
|
||||
<<"lib/oban/pro/plugins/dynamic_partitioner.ex">>,
|
||||
<<"lib/oban/pro/plugins/dynamic_lifeline.ex">>,
|
||||
<<"lib/oban/pro/plugins/dynamic_queues.ex">>,
|
||||
<<"lib/oban/pro/plugins/dynamic_cron.ex">>,<<"lib/oban/pro/limiters">>,
|
||||
<<"lib/oban/pro/limiters/local.ex">>,<<"lib/oban/pro/limiters/rate.ex">>,
|
||||
<<"lib/oban/pro/limiters/rate">>,
|
||||
<<"lib/oban/pro/limiters/rate/token_bucket.ex">>,
|
||||
<<"lib/oban/pro/limiters/rate/algorithm.ex">>,
|
||||
<<"lib/oban/pro/limiters/rate/fixed_window.ex">>,
|
||||
<<"lib/oban/pro/limiters/rate/sliding_window.ex">>,
|
||||
<<"lib/oban/pro/limiters/global.ex">>,<<"lib/oban/pro/queue.ex">>,
|
||||
<<"lib/oban/pro/handler.ex">>,<<"lib/oban/pro/partition.ex">>,
|
||||
<<"lib/oban/pro/cloud.ex">>,<<"lib/oban/pro/uuidv7.ex">>,
|
||||
<<"lib/oban/pro/stage.ex">>,<<"lib/oban/pro/refresher.ex">>,
|
||||
<<"lib/oban/pro/workflow.ex">>,<<"lib/oban/pro/testing.ex">>,
|
||||
<<"lib/oban/pro/migration.ex">>,<<"lib/oban/pro/engines">>,
|
||||
<<"lib/oban/pro/engines/smart.ex">>,<<"lib/oban/pro/workflow">>,
|
||||
<<"lib/oban/pro/workflow/schema.ex">>,
|
||||
<<"lib/oban/pro/workflow/cascade.ex">>,<<"lib/oban/pro/limiter.ex">>,
|
||||
<<"lib/oban/pro/validation.ex">>,<<"lib/oban/pro/flusher.ex">>,
|
||||
<<"lib/oban/pro/workers">>,<<"lib/oban/pro/workers/chain.ex">>,
|
||||
<<"lib/oban/pro/workers/batch.ex">>,<<"lib/oban/pro/workers/chunk.ex">>,
|
||||
<<"lib/oban/pro/workers/workflow.ex">>,<<"lib/oban/pro/application.ex">>,
|
||||
<<"lib/oban/pro/utils.ex">>,<<"lib/oban/pro/relay.ex">>,
|
||||
<<"lib/oban/pro/exceptions.ex">>,<<"lib/oban/pro/rate_limit.ex">>,
|
||||
<<"lib/oban/pro.ex">>,<<"usage-rules">>,<<"usage-rules/workflows.md">>,
|
||||
<<"usage-rules/chunks.md">>,<<"usage-rules/workers.md">>,
|
||||
<<"usage-rules/testing.md">>,<<"usage-rules/batches.md">>,
|
||||
<<"usage-rules/queues.md">>,<<"usage-rules/plugins.md">>,
|
||||
<<"usage-rules/chains.md">>,<<".formatter.exs">>,<<"mix.exs">>,
|
||||
<<"usage-rules.md">>]}.
|
||||
{<<"app">>,<<"oban_pro">>}.
|
||||
{<<"licenses">>,[<<"Commercial">>]}.
|
||||
{<<"requirements">>,
|
||||
[[{<<"name">>,<<"oban">>},
|
||||
{<<"app">>,<<"oban">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 2.21">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"ecto_sql">>},
|
||||
{<<"app">>,<<"ecto_sql">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 3.12">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"postgrex">>},
|
||||
{<<"app">>,<<"postgrex">>},
|
||||
{<<"optional">>,true},
|
||||
{<<"requirement">>,<<"~> 0.22">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"decimal">>},
|
||||
{<<"app">>,<<"decimal">>},
|
||||
{<<"optional">>,true},
|
||||
{<<"requirement">>,<<"~> 3.0">>},
|
||||
{<<"repository">>,<<"hexpm">>}]]}.
|
||||
{<<"build_tools">>,[<<"mix">>]}.
|
||||
6
vendor/oban_pro/lib/oban/pro/application.ex
vendored
6
vendor/oban_pro/lib/oban/pro/application.ex
vendored
|
|
@ -17,7 +17,11 @@ defmodule Oban.Pro.Application do
|
|||
def start(_type, _args) do
|
||||
for handler <- @handlers, do: handler.on_start()
|
||||
|
||||
children = [Oban.Pro.Diagnostics, Oban.Pro.Refresher]
|
||||
children = [
|
||||
{Oban.Pro.Diagnostics, []},
|
||||
{Oban.Pro.Refresher, []},
|
||||
{Task.Supervisor, name: Oban.Pro.TaskSupervisor}
|
||||
]
|
||||
|
||||
Supervisor.start_link(children, strategy: :one_for_one, name: __MODULE__)
|
||||
end
|
||||
|
|
|
|||
75
vendor/oban_pro/lib/oban/pro/engines/smart.ex
vendored
75
vendor/oban_pro/lib/oban/pro/engines/smart.ex
vendored
|
|
@ -517,6 +517,8 @@ defmodule Oban.Pro.Engines.Smart do
|
|||
|
||||
@registry Oban.Registry
|
||||
|
||||
@lock_codes ~w(deadlock_detected lock_not_available)a
|
||||
|
||||
@virtual_opts ~w(ack_async queue refresh_interval xact_delay xact_retry xact_timeout updated_at)a
|
||||
|
||||
@smart_opts Application.compile_env(:oban_pro, __MODULE__, [])
|
||||
|
|
@ -793,9 +795,8 @@ defmodule Oban.Pro.Engines.Smart do
|
|||
{:ok, {producer, jobs}}
|
||||
|
||||
{:error, _op, %{postgres: %{code: :unique_violation, detail: detail}}, changes} ->
|
||||
clear_uniq_violation(changes.conf, detail, ~w(available executing retryable))
|
||||
|
||||
retry_unique_violation(:fetch_jobs, [conf, producer, running])
|
||||
clear_unique_violation(changes.conf, detail, ~w(available executing retryable))
|
||||
retry_unique_violation(conf, producer, running)
|
||||
|
||||
{:error, _operation, :xact_lock, _changes} ->
|
||||
jittery_sleep()
|
||||
|
|
@ -812,16 +813,35 @@ defmodule Oban.Pro.Engines.Smart do
|
|||
end
|
||||
catch
|
||||
:error, %Postgrex.Error{postgres: %{code: :unique_violation, detail: detail}} ->
|
||||
clear_uniq_violation(conf, detail, Enum.map(Job.states(), &to_string/1))
|
||||
clear_unique_violation(conf, detail, Enum.map(Job.states(), &to_string/1))
|
||||
retry_unique_violation(conf, producer, running)
|
||||
|
||||
retry_unique_violation(:fetch_jobs, [conf, producer, running])
|
||||
|
||||
:error, %Postgrex.Error{postgres: %{code: :deadlock_detected}} ->
|
||||
:error, %Postgrex.Error{postgres: %{code: code}} when code in @lock_codes ->
|
||||
jittery_sleep()
|
||||
|
||||
fetch_jobs(conf, producer, running)
|
||||
end
|
||||
|
||||
defp retry_unique_violation(conf, producer, running) do
|
||||
attempt = Process.get(:fetch_jobs, 0)
|
||||
|
||||
if attempt >= @max_uniq_retries do
|
||||
Process.delete(:fetch_jobs)
|
||||
|
||||
Logger.error(fn ->
|
||||
"[Oban.Pro.Engines.Smart] Unique violation retry limit (#{@max_uniq_retries}) exceeded " <>
|
||||
"while fetching jobs. This may indicate a persistent unique constraint conflict that " <>
|
||||
"can't be automatically resolved."
|
||||
end)
|
||||
|
||||
{:ok, {producer, []}}
|
||||
else
|
||||
Process.put(:fetch_jobs, attempt + 1)
|
||||
|
||||
fetch_jobs(conf, producer, running)
|
||||
end
|
||||
end
|
||||
|
||||
@doc false
|
||||
def fetch_for_drain(conf, %{queue: queue, with_limit: limit} = opts) do
|
||||
subset_query =
|
||||
|
|
@ -883,9 +903,14 @@ defmodule Oban.Pro.Engines.Smart do
|
|||
{:ok, staged}
|
||||
catch
|
||||
:error, %Postgrex.Error{postgres: %{code: :unique_violation, detail: detail}} ->
|
||||
clear_uniq_violation(conf, detail, ["scheduled", "retryable"])
|
||||
# Staging runs inside the Stager's transaction, and this violation has already aborted
|
||||
# it, so the conflict can't be repaired on this connection. Repair out-of-band and skip
|
||||
# this round; the next staging pass promotes the freed jobs.
|
||||
Utils.async_maybe_await(fn ->
|
||||
clear_unique_violation(conf, detail, ["scheduled", "retryable"])
|
||||
end)
|
||||
|
||||
retry_unique_violation(:stage_jobs, [conf, queryable, opts])
|
||||
{:ok, []}
|
||||
|
||||
:error, %Postgrex.Error{postgres: %{code: :deadlock_detected}} ->
|
||||
jittery_sleep()
|
||||
|
|
@ -893,34 +918,6 @@ defmodule Oban.Pro.Engines.Smart do
|
|||
stage_jobs(conf, queryable, opts)
|
||||
end
|
||||
|
||||
defp retry_unique_violation(fun, args) do
|
||||
attempt = Process.get(fun, 0)
|
||||
|
||||
if attempt >= @max_uniq_retries do
|
||||
Process.delete(fun)
|
||||
|
||||
Logger.error(fn ->
|
||||
"[Oban.Pro.Engines.Smart] Unique violation retry limit (#{@max_uniq_retries}) exceeded " <>
|
||||
"in #{fun}. This may indicate a persistent unique constraint conflict that cannot " <>
|
||||
"be automatically resolved."
|
||||
end)
|
||||
|
||||
uniq_violation_failure(fun, args)
|
||||
else
|
||||
Process.put(fun, attempt + 1)
|
||||
|
||||
apply(__MODULE__, fun, args)
|
||||
end
|
||||
end
|
||||
|
||||
defp uniq_violation_failure(:fetch_jobs, [_conf, producer, _running]) do
|
||||
{:ok, {producer, []}}
|
||||
end
|
||||
|
||||
defp uniq_violation_failure(:stage_jobs, _args) do
|
||||
{:ok, []}
|
||||
end
|
||||
|
||||
@impl Engine
|
||||
def check_available(%Config{} = conf) do
|
||||
exists =
|
||||
|
|
@ -1044,7 +1041,7 @@ defmodule Oban.Pro.Engines.Smart do
|
|||
#
|
||||
# We find conflicting jobs by matching the unique key in meta and filtering by the expected
|
||||
# states. Clearing their `uniq_bmp` disables the unique constraint, allowing the transition.
|
||||
def clear_uniq_violation(%Config{} = conf, detail, states) do
|
||||
def clear_unique_violation(%Config{} = conf, detail, states) do
|
||||
# Match both column-based `(uniq_key)=(value)` and expression-based `((meta->>'uniq_key'))=(value)`
|
||||
# formats. The exact spacing is critical.
|
||||
pattern = ~r/\((?:uniq_key|\(meta ->> 'uniq_key'::text\))\)=\((?<key>.+)\)/
|
||||
|
|
@ -1192,7 +1189,7 @@ defmodule Oban.Pro.Engines.Smart do
|
|||
mode =
|
||||
case Repo.one(conf, query) do
|
||||
nil -> :none
|
||||
indexdef -> if String.contains?(indexdef, "(uniq_key)"), do: :column, else: :expression
|
||||
indexdef -> if indexdef =~ ~r/\(uniq_key(?:\s+ASC)?\)/, do: :column, else: :expression
|
||||
end
|
||||
|
||||
{:ok, mode}
|
||||
|
|
|
|||
54
vendor/oban_pro/lib/oban/pro/partition.ex
vendored
54
vendor/oban_pro/lib/oban/pro/partition.ex
vendored
|
|
@ -10,6 +10,7 @@ defmodule Oban.Pro.Partition do
|
|||
alias Oban.Pro.{Producer, Queue, Utils}
|
||||
|
||||
@keys_cache_ttl Application.compile_env(:oban_pro, [__MODULE__, :keys_cache_ttl], 3_000)
|
||||
@conf_cache_ttl Application.compile_env(:oban_pro, [__MODULE__, :conf_cache_ttl], 60_000)
|
||||
@keys_limit_mlt Application.compile_env(:oban_pro, [__MODULE__, :keys_limit_multiplier], 3)
|
||||
|
||||
@conf_tab Module.concat(__MODULE__, Conf)
|
||||
|
|
@ -32,7 +33,15 @@ defmodule Oban.Pro.Partition do
|
|||
|
||||
# Clear the cache with a timeout, as not all queues are guaranteed to be running on a given
|
||||
# node and the cache won't clear naturally.
|
||||
:timer.apply_interval(@keys_cache_ttl, __MODULE__, :__clear_cache__, [@keys_cache_ttl])
|
||||
:timer.apply_interval(@conf_cache_ttl, __MODULE__, :__clear_cache__, [
|
||||
@conf_tab,
|
||||
@conf_cache_ttl
|
||||
])
|
||||
|
||||
:timer.apply_interval(@keys_cache_ttl, __MODULE__, :__clear_cache__, [
|
||||
@keys_tab,
|
||||
@keys_cache_ttl
|
||||
])
|
||||
|
||||
:telemetry.attach(
|
||||
"oban.pro.partition",
|
||||
|
|
@ -47,12 +56,11 @@ defmodule Oban.Pro.Partition do
|
|||
:telemetry.detach("oban.pro.partition")
|
||||
end
|
||||
|
||||
def __clear_cache__(ttl) do
|
||||
def __clear_cache__(tab, ttl) do
|
||||
now = System.monotonic_time(:millisecond)
|
||||
spec = {{:_, :_, :"$3"}, [{:>=, {:-, now, :"$3"}, ttl}], [true]}
|
||||
|
||||
:ets.select_delete(@keys_tab, [
|
||||
{{:_, :_, :"$3"}, [{:>=, {:-, now, :"$3"}, ttl}], [true]}
|
||||
])
|
||||
:ets.select_delete(tab, [spec])
|
||||
end
|
||||
|
||||
def handle_event(_event, _measure, %{conf: conf, key: key, meta: meta}, nil) do
|
||||
|
|
@ -104,7 +112,7 @@ defmodule Oban.Pro.Partition do
|
|||
|
||||
@spec available_keys(Config.t(), String.t(), pos_integer()) :: [String.t()]
|
||||
def available_keys(conf, queue, limit) do
|
||||
timed_cache(conf.name, queue, fn ->
|
||||
Utils.ets_cache(@keys_tab, {conf.name, queue}, @keys_cache_ttl, fn ->
|
||||
query_limit = @keys_limit_mlt * limit
|
||||
|
||||
subquery =
|
||||
|
|
@ -126,21 +134,6 @@ defmodule Oban.Pro.Partition do
|
|||
end)
|
||||
end
|
||||
|
||||
defp timed_cache(name, queue, fun) do
|
||||
cache_key = {name, queue}
|
||||
now = System.monotonic_time(:millisecond)
|
||||
|
||||
case :ets.lookup(@keys_tab, cache_key) do
|
||||
[{^cache_key, keys, timestamp}] when now - timestamp < @keys_cache_ttl ->
|
||||
keys
|
||||
|
||||
_ ->
|
||||
keys = fun.()
|
||||
:ets.insert(@keys_tab, {cache_key, keys, now})
|
||||
keys
|
||||
end
|
||||
end
|
||||
|
||||
# Rescuing
|
||||
|
||||
@doc false
|
||||
|
|
@ -208,20 +201,11 @@ defmodule Oban.Pro.Partition do
|
|||
if Process.get(:oban_draining) do
|
||||
:missing
|
||||
else
|
||||
case :ets.lookup(@conf_tab, {conf.name, queue}) do
|
||||
[{_key, value}] ->
|
||||
value
|
||||
|
||||
[] ->
|
||||
value =
|
||||
with :missing <- reg_config(conf, queue),
|
||||
:missing <- pro_config(conf, queue),
|
||||
do: dyn_config(conf, queue)
|
||||
|
||||
:ets.insert(@conf_tab, {{conf.name, queue}, value})
|
||||
|
||||
value
|
||||
end
|
||||
Utils.ets_cache(@conf_tab, {conf.name, queue}, @conf_cache_ttl, fn ->
|
||||
with :missing <- reg_config(conf, queue),
|
||||
:missing <- pro_config(conf, queue),
|
||||
do: dyn_config(conf, queue)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ defmodule Oban.Pro.Plugins.DynamicLifeline do
|
|||
Repo.update_all(state.conf, query, [], timeout: state.timeout)
|
||||
catch
|
||||
:error, %Postgrex.Error{postgres: %{code: :unique_violation, detail: detail}} ->
|
||||
Smart.clear_uniq_violation(state.conf, detail, ~w(available executing retryable))
|
||||
Smart.clear_unique_violation(state.conf, detail, ~w(available executing retryable))
|
||||
|
||||
{0, []}
|
||||
end
|
||||
|
|
@ -324,7 +324,7 @@ defmodule Oban.Pro.Plugins.DynamicLifeline do
|
|||
Repo.update_all(state.conf, query, [], timeout: state.timeout)
|
||||
catch
|
||||
:error, %Postgrex.Error{postgres: %{code: :unique_violation, detail: detail}} ->
|
||||
Smart.clear_uniq_violation(state.conf, detail, ~w(available executing retryable))
|
||||
Smart.clear_unique_violation(state.conf, detail, ~w(available executing retryable))
|
||||
|
||||
{0, []}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@ defmodule Oban.Pro.Stages.Deadline do
|
|||
dat = DateTime.from_unix!(at)
|
||||
|
||||
if :gt == DateTime.compare(now, dat) do
|
||||
{:cancel, "deadline at #{inspect(dat)} exired"}
|
||||
Hooks.execute_on_cancelled(:deadline, job)
|
||||
|
||||
{:cancel, "deadline at #{inspect(dat)} expired"}
|
||||
else
|
||||
if conf.force, do: force_timeout(now, dat, job)
|
||||
|
||||
|
|
|
|||
13
vendor/oban_pro/lib/oban/pro/stages/hooks.ex
vendored
13
vendor/oban_pro/lib/oban/pro/stages/hooks.ex
vendored
|
|
@ -14,6 +14,7 @@ defmodule Oban.Pro.Stages.Hooks do
|
|||
after_cancelled: 2,
|
||||
before_new: 2,
|
||||
before_process: 1,
|
||||
after_process: 2,
|
||||
after_process: 3,
|
||||
on_cancelled: 2,
|
||||
on_discarded: 2
|
||||
|
|
@ -128,7 +129,7 @@ defmodule Oban.Pro.Stages.Hooks do
|
|||
all_hooks = Enum.uniq([worker | mod_hooks] ++ get_hooks())
|
||||
|
||||
for module <- all_hooks, hook_exported?(module, hook) do
|
||||
apply(module, hook, args)
|
||||
apply_hook(module, hook, args)
|
||||
end
|
||||
catch
|
||||
kind, value ->
|
||||
|
|
@ -137,6 +138,16 @@ defmodule Oban.Pro.Stages.Hooks do
|
|||
end)
|
||||
end
|
||||
|
||||
defp apply_hook(module, :after_process, [state, job, result]) do
|
||||
if function_exported?(module, :after_process, 3) do
|
||||
module.after_process(state, job, result)
|
||||
else
|
||||
module.after_process(state, job)
|
||||
end
|
||||
end
|
||||
|
||||
defp apply_hook(module, hook, args), do: apply(module, hook, args)
|
||||
|
||||
defp resolve_processing(job) do
|
||||
with nil <- Process.get(:oban_processing),
|
||||
{:ok, worker} <- Oban.Worker.from_string(job.worker),
|
||||
|
|
|
|||
6
vendor/oban_pro/lib/oban/pro/testing.ex
vendored
6
vendor/oban_pro/lib/oban/pro/testing.ex
vendored
|
|
@ -71,7 +71,8 @@ defmodule Oban.Pro.Testing do
|
|||
discarded: non_neg_integer(),
|
||||
exhausted: non_neg_integer(),
|
||||
retryable: non_neg_integer(),
|
||||
scheduled: non_neg_integer()
|
||||
scheduled: non_neg_integer(),
|
||||
suspended: non_neg_integer()
|
||||
}
|
||||
|
||||
@type drain_result :: drain_summary() | [Job.t()]
|
||||
|
|
@ -201,7 +202,8 @@ defmodule Oban.Pro.Testing do
|
|||
discarded: 0,
|
||||
exhausted: 0,
|
||||
retryable: 0,
|
||||
scheduled: 0
|
||||
scheduled: 0,
|
||||
suspended: 0
|
||||
}
|
||||
|
||||
@doc """
|
||||
|
|
|
|||
31
vendor/oban_pro/lib/oban/pro/utils.ex
vendored
31
vendor/oban_pro/lib/oban/pro/utils.ex
vendored
|
|
@ -28,6 +28,20 @@ defmodule Oban.Pro.Utils do
|
|||
|> Base.encode64(padding: false)
|
||||
end
|
||||
|
||||
# Caching
|
||||
|
||||
def ets_cache(tab, key, ttl, fun) when is_function(fun, 0) do
|
||||
now = System.monotonic_time(:millisecond)
|
||||
|
||||
case :ets.lookup(tab, key) do
|
||||
[{^key, value, timestamp}] when now - timestamp < ttl ->
|
||||
value
|
||||
|
||||
_ ->
|
||||
tap(fun.(), &:ets.insert(tab, {key, &1, now}))
|
||||
end
|
||||
end
|
||||
|
||||
@spec persistent_cache(tuple(), (-> any())) :: any()
|
||||
def persistent_cache(key, fun) when is_function(fun, 0) do
|
||||
persistent_cache(key, :infinity, fun)
|
||||
|
|
@ -45,6 +59,23 @@ defmodule Oban.Pro.Utils do
|
|||
end
|
||||
end
|
||||
|
||||
# Async Execution
|
||||
|
||||
def async_maybe_await(fun) when is_function(fun, 0) do
|
||||
# Await during testing to prevent leaking side-effects after a test concludes.
|
||||
if Process.get(:oban_draining) do
|
||||
Oban.Pro.TaskSupervisor
|
||||
|> Task.Supervisor.async(fun)
|
||||
|> Task.await()
|
||||
else
|
||||
Task.Supervisor.start_child(Oban.Pro.TaskSupervisor, fun)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
# Feature Detection
|
||||
|
||||
@spec has_legacy_workflows?(Oban.Config.t()) :: boolean()
|
||||
def has_legacy_workflows?(conf) do
|
||||
persistent_cache({__MODULE__, :legacy_workflows, conf.name}, @legacy_ttl, fn ->
|
||||
|
|
|
|||
24
vendor/oban_pro/lib/oban/pro/worker.ex
vendored
24
vendor/oban_pro/lib/oban/pro/worker.ex
vendored
|
|
@ -203,10 +203,10 @@ defmodule Oban.Pro.Worker do
|
|||
The example above uses `recorded: true` to opt into recording with the defaults. That means an
|
||||
output `limit` of 64mb after compression and encoding—anything larger than the configured limit
|
||||
will return an error tuple. If you expect larger results (and you want them stored in the
|
||||
database) you can override the limit. For example, to set the limit to 64mb instead:
|
||||
database) you can override the limit. For example, to set the limit to 32mb instead:
|
||||
|
||||
```elixir
|
||||
use Oban.Pro.Worker, recorded: [limit: 128_000_000]
|
||||
use Oban.Pro.Worker, recorded: [limit: 32_000_000]
|
||||
```
|
||||
|
||||
### Retrieving Results
|
||||
|
|
@ -1561,18 +1561,16 @@ defmodule Oban.Pro.Worker do
|
|||
end
|
||||
|
||||
defp await_signal(oban_name, id, wait_until, wait_timeout) do
|
||||
case Notifier.listen(oban_name, :pro_signal) do
|
||||
:ok ->
|
||||
try do
|
||||
await_loop(id, wait_until, wait_timeout)
|
||||
after
|
||||
Notifier.unlisten(oban_name, :pro_signal)
|
||||
end
|
||||
if Process.get(:oban_draining) do
|
||||
park_or_timeout(wait_until)
|
||||
else
|
||||
Notifier.listen(oban_name, :pro_signal)
|
||||
|
||||
{:error, _reason} ->
|
||||
# Without a notifier, e.g. while draining, there's no way to receive a live signal, so
|
||||
# park immediately and let a buffered signal resume the job on a later pass.
|
||||
park_or_timeout(wait_until)
|
||||
try do
|
||||
await_loop(id, wait_until, wait_timeout)
|
||||
after
|
||||
Notifier.unlisten(oban_name, :pro_signal)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
85
vendor/oban_pro/lib/oban/pro/workflow.ex
vendored
85
vendor/oban_pro/lib/oban/pro/workflow.ex
vendored
|
|
@ -1738,39 +1738,38 @@ defmodule Oban.Pro.Workflow do
|
|||
sub_changesets =
|
||||
Enum.map(sub_workflow.changesets, fn changeset ->
|
||||
meta_deps = get_in(changeset.changes, [:meta, :deps])
|
||||
context? = get_in(changeset.changes, [:meta, :context]) == true
|
||||
nested? = get_in(changeset.changes, [:meta, :sup_workflow_id]) != nil
|
||||
|
||||
if deps != [] and meta_deps == [] do
|
||||
old_ancestors = get_in(changeset.changes, [:meta, :ancestor_ids]) || []
|
||||
new_ancestors = Map.get(workflow.opts, :ancestor_ids, [])
|
||||
all_ancestors = old_ancestors ++ [workflow.id] ++ new_ancestors
|
||||
old_ancestors = get_in(changeset.changes, [:meta, :ancestor_ids]) || []
|
||||
new_ancestors = Map.get(workflow.opts, :ancestor_ids, [])
|
||||
all_ancestors = old_ancestors ++ [workflow.id] ++ new_ancestors
|
||||
|
||||
opts
|
||||
|> Map.new()
|
||||
|> Map.put(:ancestor_ids, all_ancestors)
|
||||
|> Map.put(:deps, deps)
|
||||
|> Map.put(:sub_name, name)
|
||||
|> Map.put(:sup_workflow_id, workflow.id)
|
||||
|> Map.put(:workflow_id, sub_workflow.id)
|
||||
|> put_hold(changeset)
|
||||
else
|
||||
new_ancestors = Map.get(workflow.opts, :ancestor_ids, [])
|
||||
cond do
|
||||
not context? and deps != [] and meta_deps == [] ->
|
||||
opts
|
||||
|> Map.new()
|
||||
|> Map.put(:ancestor_ids, all_ancestors)
|
||||
|> Map.put(:deps, deps)
|
||||
|> Map.put(:sub_name, name)
|
||||
|> Map.put(:sup_workflow_id, workflow.id)
|
||||
|> Map.put(:workflow_id, sub_workflow.id)
|
||||
|> put_hold(changeset)
|
||||
|
||||
meta =
|
||||
if get_in(changeset.changes, [:meta, :sup_workflow_id]) do
|
||||
old_ancestors = get_in(changeset.changes, [:meta, :ancestor_ids]) || []
|
||||
all_ancestors = old_ancestors ++ [workflow.id] ++ new_ancestors
|
||||
nested? ->
|
||||
meta = %{sup_workflow_id: workflow.id, ancestor_ids: all_ancestors}
|
||||
|
||||
%{sup_workflow_id: workflow.id, ancestor_ids: all_ancestors}
|
||||
else
|
||||
%{
|
||||
sub_name: name,
|
||||
sup_workflow_id: workflow.id,
|
||||
workflow_id: sub_workflow.id,
|
||||
ancestor_ids: [workflow.id] ++ new_ancestors
|
||||
}
|
||||
end
|
||||
Changeset.update_change(changeset, :meta, &Map.merge(&1, meta))
|
||||
|
||||
Changeset.update_change(changeset, :meta, &Map.merge(&1, meta))
|
||||
true ->
|
||||
meta = %{
|
||||
sub_name: name,
|
||||
sup_workflow_id: workflow.id,
|
||||
workflow_id: sub_workflow.id,
|
||||
ancestor_ids: [workflow.id] ++ new_ancestors
|
||||
}
|
||||
|
||||
Changeset.update_change(changeset, :meta, &Map.merge(&1, meta))
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
@ -1980,6 +1979,8 @@ defmodule Oban.Pro.Workflow do
|
|||
_ -> graft_id
|
||||
end
|
||||
|
||||
sub_id = workflow.id
|
||||
|
||||
changesets =
|
||||
Enum.map(workflow.changesets, fn changeset ->
|
||||
if get_in(changeset.changes, [:meta, :sup_workflow_id]) do
|
||||
|
|
@ -1991,9 +1992,31 @@ defmodule Oban.Pro.Workflow do
|
|||
|
||||
workflow = %{workflow | id: root_id, changesets: changesets}
|
||||
|
||||
job
|
||||
|> append(check_deps: false)
|
||||
|> add_workflow(graft_name, workflow, opts)
|
||||
grafted =
|
||||
job
|
||||
|> append(check_deps: false)
|
||||
|> add_workflow(graft_name, workflow, opts)
|
||||
|
||||
changesets = Enum.map(grafted.changesets, &reparent_grafted(&1, root_id, sub_id))
|
||||
|
||||
%{grafted | changesets: changesets}
|
||||
end
|
||||
|
||||
defp reparent_grafted(changeset, root_id, sub_id) do
|
||||
case get_in(changeset.changes, [:meta, :workflow_id]) do
|
||||
^root_id ->
|
||||
changeset
|
||||
|
||||
_ ->
|
||||
Changeset.update_change(changeset, :meta, fn meta ->
|
||||
ancestors =
|
||||
Enum.map(meta[:ancestor_ids] || [root_id], &if(&1 == sub_id, do: root_id, else: &1))
|
||||
|
||||
meta
|
||||
|> Map.put(:sup_workflow_id, root_id)
|
||||
|> Map.put(:ancestor_ids, ancestors)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
defp extract_graft! do
|
||||
|
|
|
|||
2
vendor/oban_pro/mix.exs
vendored
2
vendor/oban_pro/mix.exs
vendored
|
|
@ -1,7 +1,7 @@
|
|||
defmodule Oban.Pro.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@version "1.7.6"
|
||||
@version "1.7.7"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
|
|
|||
BIN
vendor/oban_web/.hex
vendored
BIN
vendor/oban_web/.hex
vendored
Binary file not shown.
85
vendor/oban_web/CHANGELOG.md
vendored
85
vendor/oban_web/CHANGELOG.md
vendored
|
|
@ -95,6 +95,91 @@ options and burst mode configuration.
|
|||
|
||||
### Bug Fixes
|
||||
|
||||
- [Jobs] Restrict unauthorized job editing and updates with new permission
|
||||
|
||||
The save-job event handler previously dispatched changes from any client
|
||||
without checking access controls, allowing a read-only user to rewrite a
|
||||
job's worker module and potentially trigger code execution on the next
|
||||
attempt. Editing now requires `:update_jobs` permission, which is
|
||||
enabled by default for `:all` and disabled for `:read_only`.
|
||||
|
||||
- [Cron] Prevent malicious cron expressions from unrestricted memory allocation
|
||||
|
||||
A maliciously crafted cron expression like "0 0 1--100000000 \* \*" could
|
||||
trigger multi-gigabyte allocations when `describe/1` eagerly expanded
|
||||
the range during formatting. Range, value, and step parsing now validate
|
||||
against per-field bounds and require ranges to be non-decreasing, so
|
||||
out-of-domain inputs are rejected before any expansion occurs.
|
||||
|
||||
## v2.12.5 - 2026-07-06
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [Jobs] Build jobs through worker `new/2` when available
|
||||
|
||||
The new job drawer always built changesets with `Job.new/2`, bypassing worker-level defaults,
|
||||
validation, and Pro stages (recorded, chain, etc). Now we resolve the worker module and use its
|
||||
`new/2` when it's loaded on the Web instance, falling back to `Job.new/2` when the module isn't
|
||||
available.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [Dashboard] Resolve Elixir 1.20 compilation warnings
|
||||
|
||||
Fix all of the warnings surfaced by the Elixir v1.20 type checker and upgrade any packages with
|
||||
errors or secutity warnings.
|
||||
|
||||
- [Job Details] Fix clearing tags when editing jobs
|
||||
|
||||
Treat blank tag input as an empty list when editing jobs, while leaving it as `nil` during job
|
||||
creation.
|
||||
|
||||
- [Job Details] Add clipboard fallback for insecure contexts
|
||||
|
||||
The navigator.clipboard API is only available in secure contexts (HTTPS or localhost), so
|
||||
copying job args, meta, and stacktraces failed with "navigator.clipboard is undefined" when Oban
|
||||
Web was served over plain HTTP. Fall back to execCommand so copy actions work in those
|
||||
environments.
|
||||
|
||||
- [Job Details] Fix new job form ignoring the scheduled at time
|
||||
|
||||
`DateTime.from_iso8601/1` returns a three-element tuple, but we only matched on `{:ok,
|
||||
datetime}`. That clause never matched, so parsing always returned `nil` and jobs created with a
|
||||
scheduled time ran immediately instead. Match the full tuple so the selected time is applied.
|
||||
|
||||
- [Job Details] Stack timeline labels on narrow screens
|
||||
|
||||
State boxes in the job timeline placed the state label and timestamp in a row that was too
|
||||
narrow until the xl breakpoint, causing the timestamp to wrap awkwardly and the content to
|
||||
bleed. Now the label and timestamp are stacked below xl, switching to side-by-side where there's
|
||||
room to fit them.
|
||||
|
||||
- [Cron] Fix cron and tag history queries for CockroachDB
|
||||
|
||||
The cron history and tag suggestion queries relied on the Postgres-only implicit `value` column
|
||||
name. CRDB names it after the function instead, which caused an `undefined_column` error.
|
||||
|
||||
Now the set-returning function is wrapped in a derived table with an explicit column alias for
|
||||
all engines.
|
||||
|
||||
## v2.12.5 - 2026-05-26
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [Jobs] Display awaitable signals in the job details page
|
||||
|
||||
Add a section that decodes and displays signal payloads sent via
|
||||
`Oban.Pro.Worker.signal/2`. While a job is parked waiting, the section
|
||||
shows "Awaiting Signal" with the deadline. Once a signal arrives, it
|
||||
switches to "Received Signal".
|
||||
|
||||
- [Resolver] Add `format_signal/2` resolver callback
|
||||
|
||||
This allows customizing the decoded output,mirroring what's available
|
||||
with `format_recorded/2`.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [Jobs] Restrict unauthorized job editing and updates with new permission
|
||||
|
||||
The save-job event handler previously dispatched changes from any client
|
||||
|
|
|
|||
109
vendor/oban_web/hex_metadata.config
vendored
109
vendor/oban_web/hex_metadata.config
vendored
|
|
@ -1,109 +0,0 @@
|
|||
{<<"links">>,
|
||||
[{<<"Website">>,<<"https://oban.pro">>},
|
||||
{<<"Changelog">>,
|
||||
<<"https://github.com/oban-bg/oban_web/blob/main/CHANGELOG.md">>},
|
||||
{<<"GitHub">>,<<"https://github.com/oban-bg/oban_web">>}]}.
|
||||
{<<"name">>,<<"oban_web">>}.
|
||||
{<<"version">>,<<"2.12.5">>}.
|
||||
{<<"description">>,<<"Dashboard for the Oban job orchestration framework">>}.
|
||||
{<<"elixir">>,<<"~> 1.15">>}.
|
||||
{<<"files">>,
|
||||
[<<"lib">>,<<"lib/mix">>,<<"lib/mix/tasks">>,
|
||||
<<"lib/mix/tasks/oban_web.install.ex">>,<<"lib/oban">>,<<"lib/oban/web">>,
|
||||
<<"lib/oban/web/cron.ex">>,<<"lib/oban/web/dashboard_live.ex">>,
|
||||
<<"lib/oban/web/page.ex">>,<<"lib/oban/web/telemetry.ex">>,
|
||||
<<"lib/oban/web/cache.ex">>,<<"lib/oban/web/plugins">>,
|
||||
<<"lib/oban/web/plugins/stats.ex">>,<<"lib/oban/web/queue.ex">>,
|
||||
<<"lib/oban/web/metrics.ex">>,<<"lib/oban/web/queries">>,
|
||||
<<"lib/oban/web/queries/query_helpers.ex">>,
|
||||
<<"lib/oban/web/queries/workflow_query.ex">>,
|
||||
<<"lib/oban/web/queries/cron_query.ex">>,
|
||||
<<"lib/oban/web/queries/job_query.ex">>,
|
||||
<<"lib/oban/web/queries/queue_query.ex">>,<<"lib/oban/web/router.ex">>,
|
||||
<<"lib/oban/web/components">>,<<"lib/oban/web/components/sort.ex">>,
|
||||
<<"lib/oban/web/components/icons.ex">>,
|
||||
<<"lib/oban/web/components/sidebar_components.ex">>,
|
||||
<<"lib/oban/web/components/core.ex">>,
|
||||
<<"lib/oban/web/components/layouts.ex">>,
|
||||
<<"lib/oban/web/components/layouts">>,
|
||||
<<"lib/oban/web/components/layouts/live.html.heex">>,
|
||||
<<"lib/oban/web/components/layouts/root.html.heex">>,
|
||||
<<"lib/oban/web/components/form_components.ex">>,
|
||||
<<"lib/oban/web/workflow.ex">>,<<"lib/oban/web/timezones.ex">>,
|
||||
<<"lib/oban/web/live">>,<<"lib/oban/web/live/search_component.ex">>,
|
||||
<<"lib/oban/web/live/workflows">>,
|
||||
<<"lib/oban/web/live/workflows/table_component.ex">>,
|
||||
<<"lib/oban/web/live/workflows/detail_component.ex">>,
|
||||
<<"lib/oban/web/live/shortcuts_component.ex">>,
|
||||
<<"lib/oban/web/live/theme_component.ex">>,<<"lib/oban/web/live/queues">>,
|
||||
<<"lib/oban/web/live/queues/table_component.ex">>,
|
||||
<<"lib/oban/web/live/queues/detail_component.ex">>,
|
||||
<<"lib/oban/web/live/queues/detail_instance_component.ex">>,
|
||||
<<"lib/oban/web/live/help_component.ex">>,<<"lib/oban/web/live/crons">>,
|
||||
<<"lib/oban/web/live/crons/table_component.ex">>,
|
||||
<<"lib/oban/web/live/crons/new_component.ex">>,
|
||||
<<"lib/oban/web/live/crons/detail_component.ex">>,
|
||||
<<"lib/oban/web/live/crons/helpers.ex">>,<<"lib/oban/web/live/jobs">>,
|
||||
<<"lib/oban/web/live/jobs/table_component.ex">>,
|
||||
<<"lib/oban/web/live/jobs/sidebar_component.ex">>,
|
||||
<<"lib/oban/web/live/jobs/new_component.ex">>,
|
||||
<<"lib/oban/web/live/jobs/detail_component.ex">>,
|
||||
<<"lib/oban/web/live/jobs/history_chart_component.ex">>,
|
||||
<<"lib/oban/web/live/jobs/timeline_component.ex">>,
|
||||
<<"lib/oban/web/live/jobs/chart_component.ex">>,
|
||||
<<"lib/oban/web/live/connectivity_component.ex">>,
|
||||
<<"lib/oban/web/live/instances_component.ex">>,
|
||||
<<"lib/oban/web/live/refresh_component.ex">>,<<"lib/oban/web/helpers.ex">>,
|
||||
<<"lib/oban/web/colors.ex">>,<<"lib/oban/web/cron_expr.ex">>,
|
||||
<<"lib/oban/web/application.ex">>,<<"lib/oban/web/utils.ex">>,
|
||||
<<"lib/oban/web/timing.ex">>,<<"lib/oban/web/pages">>,
|
||||
<<"lib/oban/web/pages/jobs_page.ex">>,
|
||||
<<"lib/oban/web/pages/crons_page.ex">>,
|
||||
<<"lib/oban/web/pages/queues_page.ex">>,
|
||||
<<"lib/oban/web/pages/workflows_page.ex">>,<<"lib/oban/web/resolver.ex">>,
|
||||
<<"lib/oban/web/authentication.ex">>,<<"lib/oban/web/helpers">>,
|
||||
<<"lib/oban/web/helpers/queue_helper.ex">>,<<"lib/oban/web/assets.ex">>,
|
||||
<<"lib/oban/web/search.ex">>,<<"lib/oban/web/exceptions.ex">>,
|
||||
<<"lib/oban/web.ex">>,<<"priv/static">>,<<"priv/static/app.css">>,
|
||||
<<"priv/static/fonts">>,<<"priv/static/fonts/Inter.woff2">>,
|
||||
<<"priv/static/app.js">>,<<"priv/timezones.txt">>,<<".formatter.exs">>,
|
||||
<<"mix.exs">>,<<"README.md">>,<<"CHANGELOG.md">>,<<"LICENSE.txt">>]}.
|
||||
{<<"app">>,<<"oban_web">>}.
|
||||
{<<"licenses">>,[<<"Apache-2.0">>]}.
|
||||
{<<"requirements">>,
|
||||
[[{<<"name">>,<<"jason">>},
|
||||
{<<"app">>,<<"jason">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 1.2">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"phoenix">>},
|
||||
{<<"app">>,<<"phoenix">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 1.7">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"phoenix_html">>},
|
||||
{<<"app">>,<<"phoenix_html">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 3.3 or ~> 4.0">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"phoenix_pubsub">>},
|
||||
{<<"app">>,<<"phoenix_pubsub">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 2.1">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"phoenix_live_view">>},
|
||||
{<<"app">>,<<"phoenix_live_view">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 1.0">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"oban">>},
|
||||
{<<"app">>,<<"oban">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 2.21">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"oban_met">>},
|
||||
{<<"app">>,<<"oban_met">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 1.1">>},
|
||||
{<<"repository">>,<<"hexpm">>}]]}.
|
||||
{<<"build_tools">>,[<<"mix">>]}.
|
||||
4
vendor/oban_web/lib/oban/web.ex
vendored
4
vendor/oban_web/lib/oban/web.ex
vendored
|
|
@ -7,6 +7,8 @@ defmodule Oban.Web do
|
|||
quote do
|
||||
@moduledoc false
|
||||
|
||||
use Phoenix.Component
|
||||
|
||||
import Phoenix.Controller, only: [get_csrf_token: 0, view_module: 1, view_template: 1]
|
||||
|
||||
unquote(html_helpers())
|
||||
|
|
@ -35,8 +37,6 @@ defmodule Oban.Web do
|
|||
|
||||
defp html_helpers do
|
||||
quote do
|
||||
use Phoenix.Component
|
||||
|
||||
import Oban.Web.Helpers
|
||||
import Phoenix.HTML
|
||||
import Phoenix.LiveView.Helpers
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ defmodule Oban.Web.Components.Icons do
|
|||
|
||||
attr :name, :string, required: true
|
||||
attr :class, :any, default: nil
|
||||
attr :rest, :global
|
||||
attr :rest, :global, include: ~w(rel)
|
||||
|
||||
def icon(assigns) do
|
||||
~H"""
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ defmodule Oban.Web.Crons.DetailComponent do
|
|||
priority: new_val?(parse_int(params["priority"]), get_opt(cron, "priority")),
|
||||
max_attempts: new_val?(parse_int(params["max_attempts"]), get_opt(cron, "max_attempts")),
|
||||
guaranteed: new_val?(params["guaranteed"] == "true", get_opt(cron, "guaranteed") == true),
|
||||
tags: new_val?(parse_tags(params["tags"]), get_opt(cron, "tags")),
|
||||
tags: new_val?(parse_form_tags(params), get_opt(cron, "tags")),
|
||||
args: new_val?(parse_json(params["args"]), get_opt(cron, "args"))
|
||||
]
|
||||
end
|
||||
|
|
@ -435,6 +435,9 @@ defmodule Oban.Web.Crons.DetailComponent do
|
|||
defp new_val?(val, nil, val), do: nil
|
||||
defp new_val?(val, _current, _default), do: val
|
||||
|
||||
defp parse_form_tags(%{"tags" => tags}), do: parse_tags(tags) || []
|
||||
defp parse_form_tags(_params), do: nil
|
||||
|
||||
defp get_opt(%{opts: opts}, key) do
|
||||
Map.get(opts, key)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -79,8 +79,7 @@ defmodule Oban.Web.Jobs.ChartComponent do
|
|||
class="w-3 h-3 ml-1 bg-violet-300 rounded-full"
|
||||
data-title={"Filtered by #{params_to_filters_list(@params)}"}
|
||||
phx-hook="Tippy"
|
||||
>
|
||||
</span>
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<div id="chart-c" class="flex space-x-2">
|
||||
|
|
|
|||
|
|
@ -1021,7 +1021,7 @@ defmodule Oban.Web.Jobs.DetailComponent do
|
|||
priority: new_val?(parse_int(params["priority"]), job.priority),
|
||||
max_attempts: new_val?(parse_int(params["max_attempts"]), job.max_attempts),
|
||||
scheduled_at: new_val?(parse_datetime(params["scheduled_at"]), job.scheduled_at),
|
||||
tags: new_val?(parse_tags(params["tags"]), job.tags),
|
||||
tags: new_val?(parse_edit_tags(params), job.tags),
|
||||
args: new_val?(parse_json(params["args"]), job.args)
|
||||
]
|
||||
end
|
||||
|
|
@ -1031,6 +1031,9 @@ defmodule Oban.Web.Jobs.DetailComponent do
|
|||
defp new_val?(val, val), do: nil
|
||||
defp new_val?(val, _current), do: val
|
||||
|
||||
defp parse_edit_tags(%{"tags" => tags}), do: parse_tags(tags) || []
|
||||
defp parse_edit_tags(_params), do: nil
|
||||
|
||||
defp parse_datetime(nil), do: nil
|
||||
defp parse_datetime(""), do: nil
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ defmodule Oban.Web.Jobs.NewComponent do
|
|||
with {:ok, worker} <- parse_worker(params["worker"]),
|
||||
{:ok, args} <- parse_args(params["args"]),
|
||||
{:ok, opts} <- build_opts(params) do
|
||||
changeset = Oban.Job.new(args, [{:worker, worker} | opts])
|
||||
changeset = build_changeset(worker, args, opts)
|
||||
|
||||
case Oban.insert(conf.name, changeset) do
|
||||
{:ok, job} ->
|
||||
|
|
@ -227,6 +227,13 @@ defmodule Oban.Web.Jobs.NewComponent do
|
|||
|
||||
defp parse_worker(_), do: {:error, "Worker is required"}
|
||||
|
||||
defp build_changeset(worker, args, opts) do
|
||||
case Oban.Worker.from_string(worker) do
|
||||
{:ok, module} -> module.new(args, opts)
|
||||
{:error, _reason} -> Oban.Job.new(args, [{:worker, worker} | opts])
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_args(args) when is_binary(args) do
|
||||
case parse_json(args) do
|
||||
nil -> {:error, "Args must be a valid JSON object"}
|
||||
|
|
@ -273,7 +280,7 @@ defmodule Oban.Web.Jobs.NewComponent do
|
|||
|
||||
defp parse_scheduled_at(str) when is_binary(str) do
|
||||
case DateTime.from_iso8601(str <> ":00Z") do
|
||||
{:ok, datetime} -> datetime
|
||||
{:ok, datetime, _offset} -> datetime
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ defmodule Oban.Web.Jobs.TimelineComponent do
|
|||
|
||||
~H"""
|
||||
<div
|
||||
class={"flex flex-col sm:flex-row items-center sm:justify-between h-12 sm:h-12 rounded-lg border-2 px-2 sm:px-3 #{@border_class} #{@bg_class} #{@dim_class}"}
|
||||
class={"flex flex-col xl:flex-row items-center justify-center xl:justify-between h-12 rounded-lg border-2 px-2 sm:px-3 #{@border_class} #{@bg_class} #{@dim_class}"}
|
||||
data-title={@tooltip}
|
||||
phx-hook="Tippy"
|
||||
id={"timeline-#{@state}"}
|
||||
|
|
@ -86,7 +86,7 @@ defmodule Oban.Web.Jobs.TimelineComponent do
|
|||
{@state}
|
||||
</span>
|
||||
</div>
|
||||
<span class={"hidden sm:inline text-xs tabular-nums #{@text_color}"}>
|
||||
<span class={"hidden sm:inline text-xs tabular-nums whitespace-nowrap #{@text_color}"}>
|
||||
{@timestamp || "—"}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
98
vendor/oban_web/lib/oban/web/pages/jobs_page.ex
vendored
98
vendor/oban_web/lib/oban/web/pages/jobs_page.ex
vendored
|
|
@ -335,7 +335,7 @@ defmodule Oban.Web.JobsPage do
|
|||
send(self(), :cancel_selected)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, expanded?: false)}
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("retry-jobs", _params, socket) do
|
||||
|
|
@ -343,7 +343,7 @@ defmodule Oban.Web.JobsPage do
|
|||
send(self(), :retry_selected)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, expanded?: false)}
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("delete-jobs", _params, socket) do
|
||||
|
|
@ -351,10 +351,10 @@ defmodule Oban.Web.JobsPage do
|
|||
send(self(), :delete_selected)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, expanded?: false)}
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
# Queues
|
||||
# System
|
||||
|
||||
@impl Page
|
||||
def handle_info({ref, _val}, socket) when is_reference(ref) do
|
||||
|
|
@ -365,14 +365,6 @@ defmodule Oban.Web.JobsPage do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info({:scale_queue, queue, limit}, socket) do
|
||||
Telemetry.action(:scale_queue, socket, [queue: queue, limit: limit], fn ->
|
||||
Oban.scale_queue(socket.assigns.conf.name, queue: queue, limit: limit)
|
||||
end)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info({:flash, mode, message}, socket) do
|
||||
{:noreply, put_flash_with_clear(socket, mode, message)}
|
||||
end
|
||||
|
|
@ -410,14 +402,6 @@ defmodule Oban.Web.JobsPage do
|
|||
{:noreply, assign(socket, detailed: job)}
|
||||
end
|
||||
|
||||
def handle_info({:delete_job, job}, socket) do
|
||||
Telemetry.action(:delete_jobs, socket, [job_ids: [job.id]], fn ->
|
||||
JobQuery.delete_jobs(socket.assigns.conf, [job.id])
|
||||
end)
|
||||
|
||||
{:noreply, push_patch(socket, to: oban_path(:jobs), replace: true)}
|
||||
end
|
||||
|
||||
def handle_info({:retry_job, job}, socket) do
|
||||
Telemetry.action(:retry_jobs, socket, [job_ids: [job.id]], fn ->
|
||||
JobQuery.retry_jobs(socket.assigns.conf, [job.id])
|
||||
|
|
@ -428,6 +412,14 @@ defmodule Oban.Web.JobsPage do
|
|||
{:noreply, assign(socket, detailed: job)}
|
||||
end
|
||||
|
||||
def handle_info({:delete_job, job}, socket) do
|
||||
Telemetry.action(:delete_jobs, socket, [job_ids: [job.id]], fn ->
|
||||
JobQuery.delete_jobs(socket.assigns.conf, [job.id])
|
||||
end)
|
||||
|
||||
{:noreply, push_patch(socket, to: oban_path(:jobs), replace: true)}
|
||||
end
|
||||
|
||||
def handle_info({:update_job, job, changes}, socket) do
|
||||
conf = socket.assigns.conf
|
||||
|
||||
|
|
@ -445,38 +437,7 @@ defmodule Oban.Web.JobsPage do
|
|||
end
|
||||
end
|
||||
|
||||
# Selection
|
||||
|
||||
def handle_info({:toggle_select, job_id}, socket) do
|
||||
selected = socket.assigns.selected
|
||||
|
||||
selected =
|
||||
if MapSet.member?(selected, job_id) do
|
||||
MapSet.delete(selected, job_id)
|
||||
else
|
||||
MapSet.put(selected, job_id)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
|
||||
def handle_info(:toggle_select_all, socket) do
|
||||
selected =
|
||||
if Enum.any?(socket.assigns.selected) do
|
||||
MapSet.new()
|
||||
else
|
||||
# Always include the jobs we can see currently to compensate for slower refresh rates.
|
||||
# Without this, visible jobs may not be selected and the interface looks broken.
|
||||
local_set = MapSet.new(socket.assigns.jobs, & &1.id)
|
||||
|
||||
socket.assigns.params
|
||||
|> JobQuery.all_job_ids(socket.assigns.conf)
|
||||
|> MapSet.new()
|
||||
|> MapSet.union(local_set)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
# Bulk Actions
|
||||
|
||||
def handle_info(:cancel_selected, socket) do
|
||||
job_ids = MapSet.to_list(socket.assigns.selected)
|
||||
|
|
@ -523,6 +484,39 @@ defmodule Oban.Web.JobsPage do
|
|||
{:noreply, handle_refresh(socket)}
|
||||
end
|
||||
|
||||
# Selection
|
||||
|
||||
def handle_info({:toggle_select, job_id}, socket) do
|
||||
selected = socket.assigns.selected
|
||||
|
||||
selected =
|
||||
if MapSet.member?(selected, job_id) do
|
||||
MapSet.delete(selected, job_id)
|
||||
else
|
||||
MapSet.put(selected, job_id)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
|
||||
def handle_info(:toggle_select_all, socket) do
|
||||
selected =
|
||||
if Enum.any?(socket.assigns.selected) do
|
||||
MapSet.new()
|
||||
else
|
||||
# Always include the jobs we can see currently to compensate for slower refresh rates.
|
||||
# Without this, visible jobs may not be selected and the interface looks broken.
|
||||
local_set = MapSet.new(socket.assigns.jobs, & &1.id)
|
||||
|
||||
socket.assigns.params
|
||||
|> JobQuery.all_job_ids(socket.assigns.conf)
|
||||
|> MapSet.new()
|
||||
|> MapSet.union(local_set)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
|
||||
# Param Helpers
|
||||
|
||||
defp params_with_defaults(params, socket) do
|
||||
|
|
|
|||
|
|
@ -325,6 +325,8 @@ defmodule Oban.Web.QueuesPage do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
# Single Actions
|
||||
|
||||
@impl Page
|
||||
def handle_info({:pause_queue, queue}, socket) do
|
||||
Telemetry.action(:pause_queue, socket, [queue: queue], fn ->
|
||||
|
|
@ -358,6 +360,18 @@ defmodule Oban.Web.QueuesPage do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info({:stop_queue, queue}, socket) do
|
||||
enforce_access!(:stop_queues, socket.assigns.access)
|
||||
|
||||
Telemetry.action(:stop_queue, socket, [queue: queue], fn ->
|
||||
Oban.stop_queue(socket.assigns.conf.name, queue: queue)
|
||||
end)
|
||||
|
||||
{:noreply, put_flash_with_clear(socket, :info, "Queue #{queue} stopped")}
|
||||
end
|
||||
|
||||
# Bulk Actions
|
||||
|
||||
def handle_info(:pause_queues, socket) do
|
||||
enforce_access!(:pause_queues, socket.assigns.access)
|
||||
|
||||
|
|
@ -409,41 +423,7 @@ defmodule Oban.Web.QueuesPage do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info({:stop_queue, queue}, socket) do
|
||||
enforce_access!(:stop_queues, socket.assigns.access)
|
||||
|
||||
Telemetry.action(:stop_queue, socket, [queue: queue], fn ->
|
||||
Oban.stop_queue(socket.assigns.conf.name, queue: queue)
|
||||
end)
|
||||
|
||||
{:noreply, put_flash_with_clear(socket, :info, "Queue #{queue} stopped")}
|
||||
end
|
||||
|
||||
def handle_info({:toggle_select, queue}, socket) do
|
||||
selected = socket.assigns.selected
|
||||
|
||||
selected =
|
||||
if MapSet.member?(selected, queue) do
|
||||
MapSet.delete(selected, queue)
|
||||
else
|
||||
MapSet.put(selected, queue)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
|
||||
def handle_info(:toggle_select_all, socket) do
|
||||
selected =
|
||||
if Enum.any?(socket.assigns.selected) do
|
||||
MapSet.new()
|
||||
else
|
||||
socket.assigns.params
|
||||
|> QueueQuery.all_queues(socket.assigns.conf)
|
||||
|> MapSet.new(& &1.name)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
# Scaling
|
||||
|
||||
def handle_info({:scale_queue, queue, name, node, limit}, socket) do
|
||||
meta = [queue: queue, name: name, node: node, limit: limit]
|
||||
|
|
@ -474,6 +454,36 @@ defmodule Oban.Web.QueuesPage do
|
|||
{:noreply, put_flash_with_clear(socket, :info, scale_message(queue, opts))}
|
||||
end
|
||||
|
||||
# Selection
|
||||
|
||||
def handle_info({:toggle_select, queue}, socket) do
|
||||
selected = socket.assigns.selected
|
||||
|
||||
selected =
|
||||
if MapSet.member?(selected, queue) do
|
||||
MapSet.delete(selected, queue)
|
||||
else
|
||||
MapSet.put(selected, queue)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
|
||||
def handle_info(:toggle_select_all, socket) do
|
||||
selected =
|
||||
if Enum.any?(socket.assigns.selected) do
|
||||
MapSet.new()
|
||||
else
|
||||
socket.assigns.params
|
||||
|> QueueQuery.all_queues(socket.assigns.conf)
|
||||
|> MapSet.new(& &1.name)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, selected: selected)}
|
||||
end
|
||||
|
||||
# Filtering
|
||||
|
||||
def handle_info({:params, :limit, inc}, socket) when is_integer(inc) do
|
||||
params =
|
||||
socket.assigns.params
|
||||
|
|
@ -483,6 +493,8 @@ defmodule Oban.Web.QueuesPage do
|
|||
{:noreply, push_patch(socket, to: oban_path(:queues, params), replace: true)}
|
||||
end
|
||||
|
||||
# Fallback
|
||||
|
||||
def handle_info(_, socket) do
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ defmodule Oban.Web.CronQuery do
|
|||
ranked = from t in subquery(inside), where: t.rn <= @history_limit
|
||||
|
||||
query =
|
||||
from f in fragment("json_array_elements_text(?)", ^names),
|
||||
from f in fragment("(SELECT value FROM json_array_elements_text(?) AS t(value))", ^names),
|
||||
as: :list,
|
||||
left_lateral_join: j in subquery(ranked),
|
||||
on: true,
|
||||
|
|
|
|||
|
|
@ -56,7 +56,12 @@ defmodule Oban.Web.JobQuery do
|
|||
|
||||
defmacrop json_unnest(field) do
|
||||
quote do
|
||||
fragment("json_array_elements_text(array_to_json(?))", unquote(field))
|
||||
fragment(
|
||||
"""
|
||||
(SELECT value FROM json_array_elements_text(array_to_json(?)) AS t(value))
|
||||
""",
|
||||
unquote(field)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -324,7 +329,7 @@ defmodule Oban.Web.JobQuery do
|
|||
join(query, :inner, [j], x in json_table(j.tags), on: true)
|
||||
|
||||
true ->
|
||||
join(query, :inner, [j], x in json_unnest(j.tags), on: true)
|
||||
join(query, :inner_lateral, [j], x in json_unnest(j.tags), on: true)
|
||||
end
|
||||
|
||||
query =
|
||||
|
|
|
|||
2
vendor/oban_web/mix.exs
vendored
2
vendor/oban_web/mix.exs
vendored
|
|
@ -2,7 +2,7 @@ defmodule Oban.Web.MixProject do
|
|||
use Mix.Project
|
||||
|
||||
@source_url "https://github.com/oban-bg/oban_web"
|
||||
@version "2.12.5"
|
||||
@version "2.12.6"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
|
|
|||
2
vendor/oban_web/priv/static/app.css
vendored
2
vendor/oban_web/priv/static/app.css
vendored
File diff suppressed because one or more lines are too long
2
vendor/oban_web/priv/static/app.js
vendored
2
vendor/oban_web/priv/static/app.js
vendored
|
|
@ -166,7 +166,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
|
||||
</svg>
|
||||
<span>Showing first ${t} jobs. This workflow has more jobs than can be displayed.</span>
|
||||
`,this.el.appendChild(r)},updateControlColors(){let e=this.el.querySelector("#graph-controls");if(!e)return;let t=this.isDarkMode(),n=t?"bg-gray-800":"bg-white",i=t?"border-gray-600":"border-gray-300",r=t?"text-gray-300":"text-gray-600",s=t?"hover:bg-gray-700":"hover:bg-gray-100";e.querySelectorAll("button").forEach(o=>{if(o.id==="toggle-tracking"&&this.trackActiveNode){let a=t?"bg-blue-900":"bg-blue-100",l=t?"border-blue-500":"border-blue-400",c=t?"text-blue-400":"text-blue-600";o.className=`w-8 h-8 flex items-center justify-center rounded-md border transition-colors cursor-pointer ${a} ${l} ${c}`}else o.className=`w-8 h-8 flex items-center justify-center rounded-md border transition-colors cursor-pointer ${n} ${i} ${r} ${s}`})}},Uw=$V;var WV={Completer:Ac,CronChart:$d,CronSparkline:$h,JobHistoryChart:Vd,JobsChart:Gd,HistoryBack:Xd,Instantiator:Kd,QueueDetailChart:Zd,QueueSparkline:Wh,Refresher:Jd,Relativize:Qd,Shortcuts:th,SidebarResizer:eh,Themer:Vh,TimelineConnectors:Hh,Tippy:Uh,WorkflowGraph:Uw},So;Mo.default.config({barColors:{0:"#0284c7"},shadowColor:"rgba(0, 0, 0, .3)"});window.addEventListener("phx:page-loading-start",e=>{So||(So=setTimeout(()=>Mo.default.show(),500))});window.addEventListener("phx:page-loading-stop",e=>{clearTimeout(So),So=void 0,Mo.default.hide()});window.addEventListener("phx:scroll-top",()=>{window.scrollTo({top:0,behavior:"instant"})});window.addEventListener("phx:copy-to-clipboard",e=>{let t=e.detail.text;t&&navigator.clipboard.writeText(t)});var VV=document.querySelector("meta[name='csrf-token']").getAttribute("content"),HV=document.querySelector("meta[name='live-transport']").getAttribute("content"),UV=document.querySelector("meta[name='live-path']").getAttribute("content"),YV=new LiveView.LiveSocket(UV,Phoenix.Socket,{transport:HV==="longpoll"?Phoenix.LongPoll:WebSocket,params:{_csrf_token:VV,init_state:Tc()},hooks:WV});YV.connect();})();
|
||||
`,this.el.appendChild(r)},updateControlColors(){let e=this.el.querySelector("#graph-controls");if(!e)return;let t=this.isDarkMode(),n=t?"bg-gray-800":"bg-white",i=t?"border-gray-600":"border-gray-300",r=t?"text-gray-300":"text-gray-600",s=t?"hover:bg-gray-700":"hover:bg-gray-100";e.querySelectorAll("button").forEach(o=>{if(o.id==="toggle-tracking"&&this.trackActiveNode){let a=t?"bg-blue-900":"bg-blue-100",l=t?"border-blue-500":"border-blue-400",c=t?"text-blue-400":"text-blue-600";o.className=`w-8 h-8 flex items-center justify-center rounded-md border transition-colors cursor-pointer ${a} ${l} ${c}`}else o.className=`w-8 h-8 flex items-center justify-center rounded-md border transition-colors cursor-pointer ${n} ${i} ${r} ${s}`})}},Uw=$V;var WV={Completer:Ac,CronChart:$d,CronSparkline:$h,JobHistoryChart:Vd,JobsChart:Gd,HistoryBack:Xd,Instantiator:Kd,QueueDetailChart:Zd,QueueSparkline:Wh,Refresher:Jd,Relativize:Qd,Shortcuts:th,SidebarResizer:eh,Themer:Vh,TimelineConnectors:Hh,Tippy:Uh,WorkflowGraph:Uw},So;Mo.default.config({barColors:{0:"#0284c7"},shadowColor:"rgba(0, 0, 0, .3)"});window.addEventListener("phx:page-loading-start",e=>{So||(So=setTimeout(()=>Mo.default.show(),500))});window.addEventListener("phx:page-loading-stop",e=>{clearTimeout(So),So=void 0,Mo.default.hide()});window.addEventListener("phx:scroll-top",()=>{window.scrollTo({top:0,behavior:"instant"})});window.addEventListener("phx:copy-to-clipboard",e=>{let t=e.detail.text;if(navigator.clipboard)navigator.clipboard.writeText(t);else{let n=document.createElement("textarea");n.value=t,n.style.position="fixed",n.style.opacity="0",document.body.appendChild(n),n.focus(),n.select();try{document.execCommand("copy")}finally{document.body.removeChild(n)}}});var VV=document.querySelector("meta[name='csrf-token']").getAttribute("content"),HV=document.querySelector("meta[name='live-transport']").getAttribute("content"),UV=document.querySelector("meta[name='live-path']").getAttribute("content"),YV=new LiveView.LiveSocket(UV,Phoenix.Socket,{transport:HV==="longpoll"?Phoenix.LongPoll:WebSocket,params:{_csrf_token:VV,init_state:Tc()},hooks:WV});YV.connect();})();
|
||||
/*!
|
||||
* @kurkle/color v0.3.2
|
||||
* https://github.com/kurkle/color#readme
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue