WardrikTriggers (wardrik_triggers v0.1.0-rc.1)

Copy Markdown

Asks agents something on a clock, when a feed has new entries, or when a service sends a webhook.

children = [
  {WardrikTriggers, name: MyApp.Triggers, store: store, target: {MyApp.Agents, []}}
]

:ok =
  WardrikTriggers.put(MyApp.Triggers, "acme/digest", [
    %{"name" => "daily", "every" => "0 9 * * *", "prompt" => "Write today's update."}
  ])

Each run happens once in the cluster, on the node that claims it first. It asks the agent through the WardrikTriggers.Target given as :target.

Summary

Functions

Returns a specification to start this module under a supervisor.

Asks agent_id about a request sent to its webhook trigger name.

Returns the triggers of agent_id, each with its next run. A webhook's next run is nil.

Replaces the triggers of agent_id with those fields describe.

Reads every trigger from the store again. Each node does this every :reconcile milliseconds.

Removes the trigger name of agent_id. Returns {:error, :not_found} if it has none, or {:error, reason} if the store fails.

Adds or replaces one trigger of agent_id, by its name.

Starts the triggers.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

deliver(triggers, agent_id, name, request)

@spec deliver(atom(), String.t(), String.t(), WardrikTriggers.Webhook.request()) ::
  :ok | {:error, :not_found | :busy | :no_agent | :failed}

Asks agent_id about a request sent to its webhook trigger name.

The request must verify against the trigger's secret. See WardrikTriggers.Webhook. A request already asked about returns :ok and asks nothing.

Returns {:error, :not_found} if the trigger doesn't exist, isn't a webhook, or the request fails to verify. Otherwise returns {:error, status} when the agent wasn't asked.

list(triggers, agent_id)

@spec list(atom(), String.t()) :: [{WardrikTriggers.Trigger.t(), DateTime.t() | nil}]

Returns the triggers of agent_id, each with its next run. A webhook's next run is nil.

put(triggers, agent_id, fields)

@spec put(atom(), String.t(), [map()]) :: :ok | {:error, String.t() | term()}

Replaces the triggers of agent_id with those fields describe.

A trigger whose every and timezone are unchanged keeps its next run. Returns {:error, message} if any trigger is invalid, and changes nothing. See WardrikTriggers.Trigger for the keys.

:ok =
  WardrikTriggers.put(MyApp.Triggers, "acme/digest", [
    %{"name" => "daily", "every" => "0 9 * * *", "prompt" => "Write today's update."}
  ])

Each trigger is its own write. It sets the new triggers first, then removes the others. If a write fails, it stops there and returns {:error, reason}: the triggers written before it are changed, the rest are as they were. Call put/3 again with the same fields to finish.

reconcile(triggers)

@spec reconcile(atom()) :: :ok

Reads every trigger from the store again. Each node does this every :reconcile milliseconds.

remove(triggers, agent_id, name)

@spec remove(atom(), String.t(), String.t()) :: :ok | {:error, :not_found | term()}

Removes the trigger name of agent_id. Returns {:error, :not_found} if it has none, or {:error, reason} if the store fails.

set(triggers, agent_id, fields)

@spec set(atom(), String.t(), map()) ::
  {:ok, WardrikTriggers.Trigger.t()} | {:error, String.t() | term()}

Adds or replaces one trigger of agent_id, by its name.

Returns {:error, message} if the trigger is invalid, or {:error, reason} if the store fails.

start_link(opts)

@spec start_link(keyword()) :: Supervisor.on_start()

Starts the triggers.

WardrikTriggers.start_link(name: MyApp.Triggers, store: store, target: {MyApp.Triggered, []})

Options

  • :name - required. What you pass to every other function.
  • :store - required. The WardrikStore triggers are kept in.
  • :target - required. A WardrikTriggers.Target, as {module, config}.
  • :req_options - Req options for reading feeds. [] unless set.
  • :reconcile - milliseconds between each node reading every trigger again, or :infinity. 60_000 unless set.