Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

agent: add a scheduler and start jobs from config

+118 -7
+2 -1
apps/sower_agent/lib/sower_agent/application.ex
··· 11 11 # Starts a worker by calling: SowerAgent.Worker.start_link(arg) 12 12 {SowerAgent.Client, []}, 13 13 {SowerAgent.Storage, []}, 14 - {Task.Supervisor, name: SowerAgent.TaskSupervisor} 14 + {Task.Supervisor, name: SowerAgent.TaskSupervisor}, 15 + SowerAgent.Scheduler 15 16 ] 16 17 17 18 # See https://hexdocs.pm/elixir/Supervisor.html
+3
apps/sower_agent/lib/sower_agent/client.ex
··· 29 29 {:ok, registered} <- 30 30 SowerClient.Schemas.Orchestration.Subscription.cast(response) do 31 31 Logger.debug(registered) 32 + 32 33 # Merge server-assigned sid back into agent subscription 33 34 %{agent_sub | sid: registered.sid} 34 35 else ··· 51 52 end 52 53 end) 53 54 |> Enum.reject(&is_nil/1) 55 + 56 + :ok = Enum.each(subscriptions, &SowerAgent.Subscription.start_schedule/1) 54 57 55 58 SowerAgent.Storage.put(:subscriptions, subscriptions) 56 59
+23
apps/sower_agent/lib/sower_agent/config.ex
··· 126 126 {:state_directory, Path.expand(dir)} 127 127 end 128 128 129 + def external_config({:subscriptions, subscriptions}) 130 + when is_list(subscriptions) do 131 + normalized_subscriptions = 132 + Enum.map(subscriptions, fn subscription -> 133 + case subscription do 134 + %{schedule: schedule} when is_binary(schedule) -> 135 + case Crontab.CronExpression.Parser.parse(schedule) do 136 + {:ok, cron} -> 137 + %{subscription | schedule: cron} 138 + 139 + {:error, error} -> 140 + Logger.error(msg: "Failed to parse schedule", error: error) 141 + subscription 142 + end 143 + 144 + subscription -> 145 + subscription 146 + end 147 + end) 148 + 149 + {:subscriptions, normalized_subscriptions} |> dbg() 150 + end 151 + 129 152 def external_config({:__struct__, _}), do: nil 130 153 131 154 def external_config(cfg), do: cfg
+3
apps/sower_agent/lib/sower_agent/scheduler.ex
··· 1 + defmodule SowerAgent.Scheduler do 2 + use Quantum, otp_app: :sower_agent 3 + end
+20 -5
apps/sower_agent/lib/sower_agent/subscription.ex
··· 1 1 defmodule SowerAgent.Subscription do 2 2 @moduledoc """ 3 - Agent-side subscription schema that extends the client subscription 4 - with agent-only configuration fields like polling schedules. 5 - 6 - Use `to_client_schema/1` to convert to the server-compatible schema 7 - when communicating with the Sower server. 3 + Agent has its own idea of subscription to avoid sending 4 + everything to the server m 8 5 """ 9 6 alias OpenApiSpex.Schema 10 7 require OpenApiSpex 8 + require Logger 11 9 12 10 alias SowerClient.Schemas.Orchestration.Subscription.Rule 13 11 ··· 82 80 {:ok, val} = cast(attrs) 83 81 val 84 82 end 83 + 84 + def start_schedule(%__MODULE__{sid: sid, schedule: schedule} = sub) 85 + when not is_nil(sid) and not is_nil(schedule) do 86 + SowerAgent.Scheduler.new_job() 87 + |> Quantum.Job.set_name(:"sub_#{sid}") 88 + |> Quantum.Job.set_schedule(sub.schedule) 89 + |> Quantum.Job.set_task(fn -> 90 + Logger.debug( 91 + msg: "Running subscription schedule", 92 + subscription_sid: sid, 93 + schedule: schedule 94 + ) 95 + end) 96 + |> SowerAgent.Scheduler.add_job() 97 + end 98 + 99 + def start_schedule(_), do: nil 85 100 86 101 defp build_spec do 87 102 %OpenApiSpex.OpenApi{
+1
apps/sower_agent/mix.exs
··· 26 26 # Run "mix help deps" to learn about dependencies. 27 27 defp deps do 28 28 [ 29 + {:quantum, "~> 3.0"}, 29 30 {:cuid2_ex, "~> 0.2"}, 30 31 {:deps_nix, "~> 2.0", only: [:dev]}, 31 32 {:igniter, only: [:dev, :test]},
+1 -1
dev-agent.json
··· 7 7 "seed_name": "deck", 8 8 "seed_type": "nixos", 9 9 "rules": ["source=dev"], 10 - "schedule": "*/15 * * * *", 10 + "schedule": "* * * * *", 11 11 "poll_on_connect": true 12 12 }, 13 13 {
+3
mix.lock
··· 5 5 "cloak": {:hex, :cloak, "1.1.4", "aba387b22ea4d80d92d38ab1890cc528b06e0e7ef2a4581d71c3fdad59e997e7", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "92b20527b9aba3d939fab0dd32ce592ff86361547cfdc87d74edce6f980eb3d7"}, 6 6 "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"}, 7 7 "conv_case": {:hex, :conv_case, "0.2.3", "c1455c27d3c1ffcdd5f17f1e91f40b8a0bc0a337805a6e8302f441af17118ed8", [:mix], [], "hexpm", "88f29a3d97d1742f9865f7e394ed3da011abb7c5e8cc104e676fdef6270d4b4a"}, 8 + "crontab": {:hex, :crontab, "1.2.0", "503611820257939d5d0fd272eb2b454f48a470435a809479ddc2c40bb515495c", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "ebd7ef4d831e1b20fa4700f0de0284a04cac4347e813337978e25b4cc5cc2207"}, 8 9 "cuid2_ex": {:hex, :cuid2_ex, "0.2.0", "b594696ceef7367f8bee7be0a4b07227755e90a1740d6cc73e7670d70e5454d4", [:mix], [], "hexpm", "49c3b81c1864f146e1cc3674ad3984ec16583c253e08d4d71d69b808e0054ea1"}, 9 10 "db_connection": {:hex, :db_connection, "2.8.1", "9abdc1e68c34c6163f6fb96a96532272d13ad7ca45262156ae8b7ec6d9dc4bec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61a3d489b239d76f326e03b98794fb8e45168396c925ef25feb405ed09da8fd"}, 10 11 "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, ··· 25 26 "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, 26 27 "fine": {:hex, :fine, "0.1.4", "b19a89c1476c7c57afb5f9314aed5960b5bc95d5277de4cb5ee8e1d1616ce379", [:mix], [], "hexpm", "be3324cc454a42d80951cf6023b9954e9ff27c6daa255483b3e8d608670303f5"}, 27 28 "floki": {:hex, :floki, "0.38.0", "62b642386fa3f2f90713f6e231da0fa3256e41ef1089f83b6ceac7a3fd3abf33", [:mix], [], "hexpm", "a5943ee91e93fb2d635b612caf5508e36d37548e84928463ef9dd986f0d1abd9"}, 29 + "gen_stage": {:hex, :gen_stage, "1.3.2", "7c77e5d1e97de2c6c2f78f306f463bca64bf2f4c3cdd606affc0100b89743b7b", [:mix], [], "hexpm", "0ffae547fa777b3ed889a6b9e1e64566217413d018cabd825f786e843ffe63e7"}, 28 30 "gettext": {:hex, :gettext, "1.0.2", "5457e1fd3f4abe47b0e13ff85086aabae760497a3497909b8473e0acee57673b", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "eab805501886802071ad290714515c8c4a17196ea76e5afc9d06ca85fb1bfeb3"}, 29 31 "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, 30 32 "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, ··· 57 59 "plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"}, 58 60 "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, 59 61 "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.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", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, 62 + "quantum": {:hex, :quantum, "3.5.3", "ee38838a07761663468145f489ad93e16a79440bebd7c0f90dc1ec9850776d99", [:mix], [{:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.14 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_registry, "~> 0.2", [hex: :telemetry_registry, repo: "hexpm", optional: false]}], "hexpm", "500fd3fa77dcd723ed9f766d4a175b684919ff7b6b8cfd9d7d0564d58eba8734"}, 60 63 "req": {:hex, :req, "0.5.16", "99ba6a36b014458e52a8b9a0543bfa752cb0344b2a9d756651db1281d4ba4450", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [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", "974a7a27982b9b791df84e8f6687d21483795882a7840e8309abdbe08bb06f09"}, 61 64 "rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"}, 62 65 "shortuuid": {:hex, :shortuuid, "4.1.0", "6f59470b78169c84a0cedbbe3fd4e83f0837a59877a4e1a7c0709916d54239e2", [:mix], [], "hexpm", "7336719118b3cca1ac73e95810199b0b9b7d00f9d71bd2c2d27fed4c4f74388e"},
+62
nix/packages/deps.nix
··· 267 267 in 268 268 drv; 269 269 270 + crontab = 271 + let 272 + version = "1.2.0"; 273 + drv = buildMix { 274 + inherit version; 275 + name = "crontab"; 276 + appConfigPath = ../../config; 277 + 278 + src = fetchHex { 279 + inherit version; 280 + pkg = "crontab"; 281 + sha256 = "ebd7ef4d831e1b20fa4700f0de0284a04cac4347e813337978e25b4cc5cc2207"; 282 + }; 283 + 284 + beamDeps = [ 285 + ecto 286 + ]; 287 + }; 288 + in 289 + drv; 290 + 270 291 cuid2_ex = 271 292 let 272 293 version = "0.2.0"; ··· 503 524 nimble_pool 504 525 telemetry 505 526 ]; 527 + }; 528 + in 529 + drv; 530 + 531 + gen_stage = 532 + let 533 + version = "1.3.2"; 534 + drv = buildMix { 535 + inherit version; 536 + name = "gen_stage"; 537 + appConfigPath = ../../config; 538 + 539 + src = fetchHex { 540 + inherit version; 541 + pkg = "gen_stage"; 542 + sha256 = "0ffae547fa777b3ed889a6b9e1e64566217413d018cabd825f786e843ffe63e7"; 543 + }; 506 544 }; 507 545 in 508 546 drv; ··· 1040 1078 db_connection 1041 1079 decimal 1042 1080 jason 1081 + ]; 1082 + }; 1083 + in 1084 + drv; 1085 + 1086 + quantum = 1087 + let 1088 + version = "3.5.3"; 1089 + drv = buildMix { 1090 + inherit version; 1091 + name = "quantum"; 1092 + appConfigPath = ../../config; 1093 + 1094 + src = fetchHex { 1095 + inherit version; 1096 + pkg = "quantum"; 1097 + sha256 = "500fd3fa77dcd723ed9f766d4a175b684919ff7b6b8cfd9d7d0564d58eba8734"; 1098 + }; 1099 + 1100 + beamDeps = [ 1101 + crontab 1102 + gen_stage 1103 + telemetry 1104 + telemetry_registry 1043 1105 ]; 1044 1106 }; 1045 1107 in