# DSL: Ash.Notifier.PubSub Ash includes a builtin notifier to help you publish events over any kind of pub-sub pattern. This is plug and play with `Phoenix.PubSub`, but could be used with any pubsub pattern. You configure a module that defines a `broadcast/3` function, and then add some "publications" which configure under what conditions an event should be sent and what the topic should be. For the full DSL spec see `Ash.Notifier.PubSub` ## Debugging PubSub It can be quite frustrating when setting up pub_sub when everything appears to be set up properly, but you aren't receiving events. This usually means some kind of mismatch between the event names produced by the resource/config of your publications, and you can use the following flag to display debug information about pub sub events coming from `Ash.Notifier.PubSub` ```elixir config :ash, :pub_sub, debug?: true ``` ## Topic Templates Often you want to include some piece of data in the thing being changed, like the `:id` attribute. This is done by providing a list as the topic, and using atoms which will be replaced by their corresponding values. They will ultimately be joined with `:`. For example: ```elixir prefix "user" publish :create, ["created", :user_id] ``` This might publish a message to "user:created:1" for example. For updates, if the field in the template is being changed, a message is sent to *both* values. So if you change `user 1` to `user 2`, the same message would be published to `user:updated:1` and `user:updated:2`. If there are multiple attributes in the template, and they are all being changed, a message is sent for every combination of substitutions. ## Important If the previous value was `nil` or the field was not selected on the data passed into the action, then a notification is not sent for the previous value. If the new value is `nil` then a notification is not sent for the new value. ## Template parts Templates may contain lists, in which case all combinations of values in the list will be used. Add `nil` to the list if you want to produce a pattern where that entry is omitted. The atom `:_tenant` may be used. If the changeset has a tenant set on it, that value will be used, otherwise that combination of values is ignored. The atom `:_pkey` may be used. It will be a stringified, concatenation of the primary key fields, or just the primary key if there is only one primary key field. The atom `nil` may be used. It only makes sense to use it in the context of a list of alternatives, and adds a pattern where that part is skipped. ```elixir publish :updated, [[:team_id, :_tenant], "updated", [:id, nil]] ``` Would produce the following messages, given a `team_id` of 1, a `tenant` of `org_1`, and an `id` of `50`: ```elixir "1:updated:50" "1:updated" "org_1:updated:50" "org_1:updated" ``` ## Custom Delimiters It's possible to change the default delimiter used when generating topics. This is useful when working with message brokers like RabbitMQ, which rely on a different set of delimiters for routing. ```elixir pub_sub do delimiter "." end ``` ## Named Pubsub modules If you are using a phoenix `Endpoint` module for pubsub then this is unnecessary. If you want to use a custom pub sub started with something like `{Phoenix.PubSub, name: MyName}`, then you can provide `MyName` to here. ## Broadcast Types Configured with `broadcast_type`. - `:notification` just sends the notification - `:phoenix_broadcast` sends a `%Phoenix.Socket.Broadcast{}` (see above) - `:broadcast` sends `%{topic: (topic), event: (event), notification: (notification)}` ## pub_sub A section for configuring how resource actions are published over pubsub See `Ash.Notifier.PubSub` and the [Notifiers](/documentation/topics/notifiers.md) guide for more. ### Nested DSLs * [publish](#pub_sub-publish) * [publish_all](#pub_sub-publish_all) ### Examples ``` pub_sub do module MyEndpoint prefix "post" publish :destroy, ["foo", :id] publish :update, ["bar", :name] event: "name_change" publish_all :create, "created" end ``` ### Options | Name | Type | Default | Docs | |------|------|---------|------| | [`module`](#pub_sub-module){: #pub_sub-module .spark-required} | `atom` | | The module to call `broadcast/3` on e.g module.broadcast(topic, event, message). | | [`prefix`](#pub_sub-prefix){: #pub_sub-prefix } | `String.t` | | A prefix for all pubsub messages, e.g `users`. A message with `created` would be published as `users:created` | | [`delimiter`](#pub_sub-delimiter){: #pub_sub-delimiter } | `String.t` | | A delimiter for building topics. Default is a colon (:) | | [`broadcast_type`](#pub_sub-broadcast_type){: #pub_sub-broadcast_type } | `:notification \| :phoenix_broadcast \| :broadcast` | `:notification` | What shape the event payloads will be in. See | | [`name`](#pub_sub-name){: #pub_sub-name } | `atom` | | A named pub sub to pass as the first argument to broadcast. | ## pub_sub.publish ```elixir publish action, topic ``` Configure a given action to publish its results over a given topic. See `Ash.Notifier.PubSub` and the [Notifiers](/documentation/topics/notifiers.md) guides for more. ### Examples ``` publish :create, "created" ``` ``` publish :assign, "assigned" ``` ### Arguments | Name | Type | Default | Docs | |------|------|---------|------| | [`action`](#pub_sub-publish-action){: #pub_sub-publish-action .spark-required} | `atom` | | The name of the action that should be published | | [`topic`](#pub_sub-publish-topic){: #pub_sub-publish-topic .spark-required} | `any` | | The topic to publish | ### Options | Name | Type | Default | Docs | |------|------|---------|------| | [`previous_values?`](#pub_sub-publish-previous_values?){: #pub_sub-publish-previous_values? } | `boolean` | `false` | Whether or not to publish messages with both the new values and the old values for referencing changed attributes | | [`event`](#pub_sub-publish-event){: #pub_sub-publish-event } | `String.t` | | The name of the event to publish. Defaults to the action name | | [`dispatcher`](#pub_sub-publish-dispatcher){: #pub_sub-publish-dispatcher } | `atom` | | The module to use as a dispatcher. If none is set, the pubsub module provided is used. | ### Introspection Target: `Ash.Notifier.PubSub.Publication` ## pub_sub.publish_all ```elixir publish_all type, topic ``` Works just like `publish`, except that it takes a type and publishes all actions of that type See `Ash.Notifier.PubSub` and the [Notifiers](/documentation/topics/notifiers.md) guides for more. ### Examples ``` publish_all :create, "created" ``` ### Arguments | Name | Type | Default | Docs | |------|------|---------|------| | [`type`](#pub_sub-publish_all-type){: #pub_sub-publish_all-type } | `:create \| :update \| :destroy` | | Publish on all actions of a given type | | [`topic`](#pub_sub-publish_all-topic){: #pub_sub-publish_all-topic .spark-required} | `any` | | The topic to publish | ### Options | Name | Type | Default | Docs | |------|------|---------|------| | [`action`](#pub_sub-publish_all-action){: #pub_sub-publish_all-action } | `atom` | | The name of the action that should be published | | [`previous_values?`](#pub_sub-publish_all-previous_values?){: #pub_sub-publish_all-previous_values? } | `boolean` | `false` | Whether or not to publish messages with both the new values and the old values for referencing changed attributes | | [`event`](#pub_sub-publish_all-event){: #pub_sub-publish_all-event } | `String.t` | | The name of the event to publish. Defaults to the action name | | [`dispatcher`](#pub_sub-publish_all-dispatcher){: #pub_sub-publish_all-dispatcher } | `atom` | | The module to use as a dispatcher. If none is set, the pubsub module provided is used. | ### Introspection Target: `Ash.Notifier.PubSub.Publication`