EctoPGMQ.PGMQ (ecto_pgmq v2.0.0)

Copy Markdown View Source

An SDK that fully covers the PGMQ API-space.

Instead of implementing a corresponding function for every alias and parameterization supported by PGMQ, this module relies on client-side defaults to implement a single function for each distinct piece of PGMQ functionality.

Partitioning

PGMQ supports partitioning both queues and archives.

The pg_partman extension must be available in order to use partitioning.

For more information about partitioning, see the PGMQ docs.

Polling

PGMQ supports Postgres server-side polling during read operations. Reading with a poll can be used to reduce network round trips if there is a good chance that demand can be satisfied in a short time BUT doing so utilizes a connection for the duration of the read operation. As such, polling should be avoided in situations where the DB connection pool is a bottleneck.

Query Options

All of the functions in this module support a common set of query options.

For a detailed description of these options, see query_opt/0.

Summary

Types

Filter conditions to be applied when reading messages from a queue.

A delay before a message becomes visible.

The number of partitions to create preemptively.

The interval at which new partitions should be created.

A message payload.

The time (in milliseconds) to wait between polls.

The maximum time (in seconds) to poll for messages.

The number of purged messages.

The maximum number of messages to read.

A query configuration option.

A map of queues and the IDs of the messages that were sent to them.

The interval at which old partitions should be dropped.

A PGMQ routing key.

The minimum time (in milliseconds) between notifications.

The time from now (in seconds) that a message is invisible.

Functions

Archives the given messages in the given queue.

Binds the given queue to the given pattern.

Creates an index to optimize FIFO message group read performance for the given queue.

Creates an unpartitioned queue with the given name.

Creates an unlogged queue with the given name.

Deletes the given messages from the given queue.

Disables insert notifications for the given queue.

Drops the given queue.

Enables insert notifications for the given queue.

Lists all insert notification throttles.

Lists all queues.

Lists all topic bindings.

Returns metrics for all queues.

Simultaneously fetches and deletes messages from the given queue.

Purges all messages from the given queue and returns the number of messages that were deleted.

Reads messages from the given queue while respecting FIFO message groups and optimizing throughput.

Reads messages from the given queue while respecting FIFO message groups and returning a single message per group.

Reads messages from the given queue with a Postgres server-side poll while respecting FIFO message groups and returning a single message per group.

Reads messages from the given queue while respecting FIFO message groups and round-robin interleaving FIFO message groups.

Reads messages from the given queue with a Postgres server-side poll while respecting FIFO message groups and round-robin interleaving FIFO message groups.

Reads messages from the given queue with a Postgres server-side poll while respecting FIFO message groups and optimizing throughput.

Sets the visibility timeout of the given messages in the given queue.

Returns all of the bindings that match the given routing key.

Unbinds the given queue from the given pattern.

Updates the insert notification throttle for the given queue.

Validates the given routing key.

Validates the given binding pattern.

Types

conditional()

@type conditional() :: %{optional(String.t()) => term()}

Filter conditions to be applied when reading messages from a queue.

Note that the filter conditions are applied to the message body, not the headers.

Experimental Feature

As stated in the PGMQ docs, conditional message reading is an experimental feature and the API might be subject to change in future releases.

delay()

@type delay() :: non_neg_integer() | DateTime.t()

A delay before a message becomes visible.

This can take either of the following forms:

  • An integer/0 denoting the time (in seconds) to wait before a message becomes visible.

  • A DateTime.t/0 denoting when a message should become visible.

leading_partitions()

@type leading_partitions() :: non_neg_integer()

The number of partitions to create preemptively.

partition_interval()

@type partition_interval() :: pos_integer() | Duration.t()

The interval at which new partitions should be created.

This can take either of the following forms:

payload()

@type payload() :: %{optional(String.Chars.t()) => term()}

A message payload.

poll_interval()

@type poll_interval() :: pos_integer()

The time (in milliseconds) to wait between polls.

poll_timeout()

@type poll_timeout() :: pos_integer()

The maximum time (in seconds) to poll for messages.

purged_messages()

@type purged_messages() :: non_neg_integer()

The number of purged messages.

quantity()

@type quantity() :: pos_integer()

The maximum number of messages to read.

query_opt()

@type query_opt() :: {:log, boolean()} | {:timeout, timeout()}

A query configuration option.

The following query configuration options are supported:

  • :log - A boolean/0 denoting whether or not to log the query. Defaults to true.

  • :timeout - A timeout/0 for the query (in milliseconds). Defaults to 15_000.

queue_message_ids()

@type queue_message_ids() :: %{
  optional(EctoPGMQ.Queue.name()) => [EctoPGMQ.Message.id()]
}

A map of queues and the IDs of the messages that were sent to them.

retention_interval()

@type retention_interval() :: pos_integer() | Duration.t()

The interval at which old partitions should be dropped.

This can take either of the following forms:

routing_key()

@type routing_key() :: String.t()

A PGMQ routing key.

Routing keys must meet the following conditions:

  • Must only contain alphanumeric characters, dots (.), hyphens (-), and underscores (_).

  • Cannot start with a dot.

  • Cannot contain consecutive dots.

  • Cannot be longer than 255 characters.

Routing keys can be validated with validate_routing_key/3.

For more information about message routing, see Message Routing.

throttle_interval()

@type throttle_interval() :: non_neg_integer()

The minimum time (in milliseconds) between notifications.

A throttle interval of 0 effectively disables notification throttling.

For more information about notification throttling, see Throttling.

visibility_timeout()

@type visibility_timeout() :: integer()

The time from now (in seconds) that a message is invisible.

Functions

archive(repo, queue, message_ids, opts \\ [])

@spec archive(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [EctoPGMQ.Message.id()], [
  query_opt()
]) :: :ok

Archives the given messages in the given queue.

For more information about this function, see the PGMQ docs.

Examples

iex> message_ids = PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}, %{"id" => 2}])
iex> PGMQ.archive(Repo, "my_queue", message_ids)
:ok

bind_topic(repo, pattern, queue, opts \\ [])

@spec bind_topic(Ecto.Repo.t(), EctoPGMQ.Binding.pattern(), EctoPGMQ.Queue.name(), [
  query_opt()
]) :: :ok

Binds the given queue to the given pattern.

For more information about message routing, see Message Routing.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.bind_topic(Repo, "#", "my_queue")
:ok

convert_archive_partitioned(repo, queue, partition_interval \\ 10000, retention_interval \\ 100_000, leading_partitions \\ 10, opts \\ [])

@spec convert_archive_partitioned(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  partition_interval(),
  retention_interval(),
  leading_partitions(),
  [query_opt()]
) :: :ok

Converts the archive for the given queue into a partitioned table.

Previous Archive

This function postfixes the old archive table name with _old and leaves its contents untouched. Additional cleanup (table deletion, message movement, etc.) is left to the user.

For more information about partitioning, see Partitioning.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.convert_archive_partitioned(Repo, "my_queue", 10_000, 100_000, 10)
:ok

iex> partition = Duration.new!(hour: 1)
iex> retention = Duration.new!(day: 1)
iex> PGMQ.convert_archive_partitioned(Repo, "my_queue", partition, retention, 10)
:ok

create_fifo_index(repo, queue, opts \\ [])

@spec create_fifo_index(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [query_opt()]) :: :ok

Creates an index to optimize FIFO message group read performance for the given queue.

For more information about FIFO message groups, see FIFO Message Groups.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.create_fifo_index(Repo, "my_queue")
:ok

create_non_partitioned(repo, queue, opts \\ [])

@spec create_non_partitioned(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [query_opt()]) ::
  :ok

Creates an unpartitioned queue with the given name.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.create_non_partitioned(Repo, "my_unpartitioned_queue")
:ok

create_partitioned(repo, queue, partition_interval \\ 10000, retention_interval \\ 100_000, opts \\ [])

@spec create_partitioned(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  partition_interval(),
  retention_interval(),
  [query_opt()]
) :: :ok

Creates a partitioned queue with the given name.

For more information about partitioning, see Partitioning.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.create_partitioned(Repo, "my_partitioned_queue", 10_000, 100_000)
:ok

iex> partition = Duration.new!(hour: 1)
iex> retention = Duration.new!(day: 1)
iex> PGMQ.create_partitioned(Repo, "my_partitioned_queue", partition, retention)
:ok

create_unlogged(repo, queue, opts \\ [])

@spec create_unlogged(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [query_opt()]) :: :ok

Creates an unlogged queue with the given name.

For more information about this function, see the PGMQ docs.

Unlogged Tables

Unlogged tables benefit from faster write operations but they risk data loss if the Postgres server restarts. Use with caution.

Examples

iex> PGMQ.create_unlogged(Repo, "my_unlogged_queue")
:ok

delete(repo, queue, message_ids, opts \\ [])

@spec delete(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [EctoPGMQ.Message.id()], [
  query_opt()
]) :: :ok

Deletes the given messages from the given queue.

For more information about this function, see the PGMQ docs.

Examples

iex> message_ids = PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}, %{"id" => 2}])
iex> PGMQ.delete(Repo, "my_queue", message_ids)
:ok

disable_notify_insert(repo, queue, opts \\ [])

@spec disable_notify_insert(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [query_opt()]) ::
  :ok

Disables insert notifications for the given queue.

For more information about notifications, see EctoPGMQ.Notifications.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.enable_notify_insert(Repo, "my_queue")
iex> PGMQ.disable_notify_insert(Repo, "my_queue")
:ok

drop_queue(repo, queue, opts \\ [])

@spec drop_queue(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [query_opt()]) :: :ok

Drops the given queue.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.drop_queue(Repo, "my_queue")
:ok

enable_notify_insert(repo, queue, throttle_interval \\ 250, opts \\ [])

@spec enable_notify_insert(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  throttle_interval(),
  [query_opt()]
) ::
  :ok

Enables insert notifications for the given queue.

For more information about notifications, see EctoPGMQ.Notifications.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.enable_notify_insert(Repo, "my_queue", 1_000)
:ok

list_notify_insert_throttles(repo, opts \\ [])

@spec list_notify_insert_throttles(Ecto.Repo.t(), [query_opt()]) :: [
  EctoPGMQ.Throttle.t()
]

Lists all insert notification throttles.

For more information about notifications, see EctoPGMQ.Notifications.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.enable_notify_insert(Repo, "my_queue")
iex> [%Throttle{} | _] = PGMQ.list_notify_insert_throttles(Repo)

list_queues(repo, opts \\ [])

@spec list_queues(Ecto.Repo.t(), [query_opt()]) :: [EctoPGMQ.Queue.t()]

Lists all queues.

Because this function naively wraps the corresponding PGMQ function, the :bindings, :metrics and :notifications fields in the returned EctoPGMQ.Queue structs will not be populated.

For more information about this function, see the PGMQ docs.

Examples

iex> [%Queue{} | _] = PGMQ.list_queues(Repo)

list_topic_bindings(repo, opts \\ [])

@spec list_topic_bindings(Ecto.Repo.t(), [query_opt()]) :: [EctoPGMQ.Binding.t()]

Lists all topic bindings.

For more information about message routing, see Message Routing.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.bind_topic(Repo, "#", "my_queue")
iex> [%Binding{} | _] = PGMQ.list_topic_bindings(Repo)

metrics_all(repo, opts \\ [])

@spec metrics_all(Ecto.Repo.t(), [query_opt()]) :: [EctoPGMQ.Metrics.t()]

Returns metrics for all queues.

For more information about this function, see the PGMQ docs.

Examples

iex> [%Metrics{} | _] = PGMQ.metrics_all(Repo)

pop(repo, queue, quantity, opts \\ [])

Simultaneously fetches and deletes messages from the given queue.

This function does NOT increment the read count of the fetched messages.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 0}] = PGMQ.pop(Repo, "my_queue", 1)

purge_queue(repo, queue, opts \\ [])

@spec purge_queue(Ecto.Repo.t(), EctoPGMQ.Queue.name(), [query_opt()]) ::
  purged_messages()

Purges all messages from the given queue and returns the number of messages that were deleted.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> PGMQ.purge_queue(Repo, "my_queue")
1

read(repo, queue, visibility_timeout, quantity, conditional \\ %{}, opts \\ [])

Reads messages from the given queue.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read(Repo, "my_queue", 5, 1)

read_grouped(repo, queue, visibility_timeout, quantity, opts \\ [])

Reads messages from the given queue while respecting FIFO message groups and optimizing throughput.

For more information about FIFO message groups, see FIFO Message Groups.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read_grouped(Repo, "my_queue", 5, 1)

read_grouped_head(repo, queue, visibility_timeout, quantity, opts \\ [])

@spec read_grouped_head(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  visibility_timeout(),
  quantity(),
  [
    query_opt()
  ]
) :: [EctoPGMQ.Message.t()]

Reads messages from the given queue while respecting FIFO message groups and returning a single message per group.

For more information about FIFO message groups, see FIFO Message Groups.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read_grouped_head(Repo, "my_queue", 5, 1)

read_grouped_head_with_poll(repo, queue, visibility_timeout, quantity, poll_timeout \\ 5, poll_interval \\ 100, opts \\ [])

@spec read_grouped_head_with_poll(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  visibility_timeout(),
  quantity(),
  poll_timeout(),
  poll_interval(),
  [query_opt()]
) :: [EctoPGMQ.Message.t()]

Reads messages from the given queue with a Postgres server-side poll while respecting FIFO message groups and returning a single message per group.

For more information about FIFO message groups, see FIFO Message Groups.

For more information about polling, see Polling.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read_grouped_head_with_poll(Repo, "my_queue", 5, 1, 5, 500)

read_grouped_rr(repo, queue, visibility_timeout, quantity, opts \\ [])

@spec read_grouped_rr(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  visibility_timeout(),
  quantity(),
  [
    query_opt()
  ]
) :: [EctoPGMQ.Message.t()]

Reads messages from the given queue while respecting FIFO message groups and round-robin interleaving FIFO message groups.

For more information about FIFO message groups, see FIFO Message Groups.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read_grouped_rr(Repo, "my_queue", 5, 1)

read_grouped_rr_with_poll(repo, queue, visibility_timeout, quantity, poll_timeout \\ 5, poll_interval \\ 100, opts \\ [])

@spec read_grouped_rr_with_poll(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  visibility_timeout(),
  quantity(),
  poll_timeout(),
  poll_interval(),
  [query_opt()]
) :: [EctoPGMQ.Message.t()]

Reads messages from the given queue with a Postgres server-side poll while respecting FIFO message groups and round-robin interleaving FIFO message groups.

For more information about FIFO message groups, see FIFO Message Groups.

For more information about polling, see Polling.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read_grouped_rr_with_poll(Repo, "my_queue", 5, 1, 5, 500)

read_grouped_with_poll(repo, queue, visibility_timeout, quantity, poll_timeout \\ 5, poll_interval \\ 100, opts \\ [])

Reads messages from the given queue with a Postgres server-side poll while respecting FIFO message groups and optimizing throughput.

For more information about FIFO message groups, see FIFO Message Groups.

For more information about polling, see Polling.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read_grouped_with_poll(Repo, "my_queue", 5, 1, 5, 500)

read_with_poll(repo, queue, visibility_timeout, quantity, poll_timeout \\ 5, poll_interval \\ 100, conditional \\ %{}, opts \\ [])

Reads messages from the given queue with a Postgres server-side poll.

For more information about polling, see Polling.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [%Message{reads: 1}] = PGMQ.read_with_poll(Repo, "my_queue", 5, 1, 5, 500)

send_batch(repo, queue, payloads, headers \\ nil, delay \\ 0, opts \\ [])

@spec send_batch(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  [payload() | nil],
  [EctoPGMQ.Message.headers() | nil] | nil,
  delay(),
  [query_opt()]
) :: [EctoPGMQ.Message.id()]

Sends the given messages to the given queue.

For more information about this function, see the PGMQ docs.

Examples

iex> [message_id] = PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> is_integer(message_id)
true

iex> delay = DateTime.utc_now()
iex> [message_id] = PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}], nil, delay)
iex> is_integer(message_id)
true

send_batch_topic(repo, routing_key, payloads, headers \\ nil, delay \\ 0, opts \\ [])

@spec send_batch_topic(
  Ecto.Repo.t(),
  routing_key(),
  [payload() | nil],
  [EctoPGMQ.Message.headers() | nil] | nil,
  delay(),
  [query_opt()]
) :: queue_message_ids()

Sends the given messages with the given routing key.

For more information about message routing, see Message Routing.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.bind_topic(Repo, "#", "my_queue")
iex> %{"my_queue" => [message_id]} = PGMQ.send_batch_topic(Repo, "my.routing.key", [%{"id" => 1}])
iex> is_integer(message_id)
true

iex> delay = DateTime.utc_now()
iex> PGMQ.bind_topic(Repo, "#", "my_queue")
iex> %{"my_queue" => [message_id]} = PGMQ.send_batch_topic(Repo, "my.routing.key", [%{"id" => 1}], nil, delay)
iex> is_integer(message_id)
true

set_vt(repo, queue, message_ids, delay, opts \\ [])

Sets the visibility timeout of the given messages in the given queue.

For more information about this function, see the PGMQ docs.

Examples

iex> message_ids = PGMQ.send_batch(Repo, "my_queue", [%{"id" => 1}])
iex> [read_message] = PGMQ.read(Repo, "my_queue", 5, 1)
iex> [updated_message] = PGMQ.set_vt(Repo, "my_queue", message_ids, 10)
iex> DateTime.diff(updated_message.visible_at, read_message.visible_at) > 0
true

test_routing(repo, routing_key, opts \\ [])

@spec test_routing(Ecto.Repo.t(), routing_key(), [query_opt()]) :: [
  EctoPGMQ.Binding.t()
]

Returns all of the bindings that match the given routing key.

Because this function naively wraps the corresponding PGMQ function, the :bound_at field in the returned EctoPGMQ.Binding structs will not be populated.

For more information about message routing, see Message Routing.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.bind_topic(Repo, "#", "my_queue")
iex> [%Binding{pattern: "#", queue: "my_queue"}] = PGMQ.test_routing(Repo, "my.routing.key")

unbind_topic(repo, pattern, queue, opts \\ [])

@spec unbind_topic(Ecto.Repo.t(), EctoPGMQ.Binding.pattern(), EctoPGMQ.Queue.name(), [
  query_opt()
]) ::
  :ok

Unbinds the given queue from the given pattern.

For more information about message routing, see Message Routing.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.bind_topic(Repo, "#", "my_queue")
iex> PGMQ.unbind_topic(Repo, "#", "my_queue")
:ok

update_notify_insert(repo, queue, throttle_interval, opts \\ [])

@spec update_notify_insert(
  Ecto.Repo.t(),
  EctoPGMQ.Queue.name(),
  throttle_interval(),
  [query_opt()]
) ::
  :ok

Updates the insert notification throttle for the given queue.

For more information about notifications, see EctoPGMQ.Notifications.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.enable_notify_insert(Repo, "my_queue")
iex> PGMQ.update_notify_insert(Repo, "my_queue", 500)
:ok

validate_routing_key(repo, routing_key, opts \\ [])

@spec validate_routing_key(Ecto.Repo.t(), routing_key(), [query_opt()]) :: :ok

Validates the given routing key.

Invalid Routing Key

This function will raise a Postgrex.Error if an invalid routing key is given.

For more information about message routing, see Message Routing.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.validate_routing_key(Repo, "my.routing.key")
:ok

validate_topic_pattern(repo, pattern, opts \\ [])

@spec validate_topic_pattern(Ecto.Repo.t(), EctoPGMQ.Binding.pattern(), [query_opt()]) ::
  :ok

Validates the given binding pattern.

Invalid Pattern

This function will raise a Postgrex.Error if an invalid pattern is given.

For more information about message routing, see Message Routing.

For more information about this function, see the PGMQ docs.

Examples

iex> PGMQ.validate_topic_pattern(Repo, "#")
:ok