diff --git a/examples.md b/examples.md deleted file mode 100644 index e11bf3e..0000000 --- a/examples.md +++ /dev/null @@ -1,178 +0,0 @@ -# Examples - -## Example 1: Guest Skeleton Usage - -The guest will implement the methods in [`wit/guest.wit`](/wit/guest.wit): -- `configure()`, which will be called by the host to setup long-lived subscriptions, and receive any other implementor specific extensions/config.. -- `handler()`, which will be called by the host to handle messages sent to the channels subscribed to in `configure()`. - -As Wasm modules/components are mostly intended to be short-lived, the host is meant to create new instances for configuration and each message handling. - -### Rust - -```rust -use crate::messaging_types::{GuestConfigurationResult, MessageResult}; - -wit_bindgen::generate!({ - path: "../wit", -}); - -struct MyGuest; - -impl guest::Guest for MyGuest { - fn configure() -> Result { - // Configure the messaging system - } - - fn handler(_ms: Vec) -> Result<(), u32> { - // Handle the message - } -} - -export_messaging!(MyGuest); -``` - -### C/C++ - -```c -#include "messaging.c" - -messaging_result_guest_configuration_error_t messaging_configure(void) { - // Configure the messaging system -} - -messaging_result_void_error_t messaging_handle(messaging_list_message_t *message) { - // Handle the message -} -``` - -### Go - -```go -package main - -import ( - msging "app/gen" -) - -func init() { - a := MsgingImpl{} - msging.SetExportsWasiMessagingMessagingGuest(a) -} - -type MsgingImpl struct { -} - -func (e MessagingImpl) Configure msging.Result[msging.WasiMessagingConsumerGuestConfiguration, msging.WasiMessagingMessagingGuestError] { - // Configure the messaging system -} - -func (e MessagingImpl) Handler msging.Result[struct{}, msging.WasiMessagingMessagingGuestError] { - // Handle the message -} - -func main() {} -``` - -## Example 2: Guest Usage - -### Rust - -```rust -use crate::messaging_types::{GuestConfigurationResult, MessageResult, connect, disconnect}; - -wit_bindgen::generate!({ - path: "../wit", -}); - -struct MyGuest; - -impl guest::Guest for MyGuest { - fn configure() -> Result { - // This function will be called by the host, who will be maintaining a - // long-lived client connection to a broker or other messaging system. - // The client will be subscribed to channels a, b, and c) with no extra configuration. - // As soon as configuration is set, the host should kill the Wasm instance. - Ok(GuestConfigurationResult { - channels: vec!["a".to_string(), "b".to_string(), "c".to_string()], - ..Default::default() - }) - } - - fn handler(ms: Vec) -> Result<(), u32> { - // Whenever a message is received on a subscribed channel (from configure()), - // the host will call this function. Once the message has been handled, - // the host is expected to kill the Wasm instance. - - for m in ms { - - // match on message metadata for channel name - match m.metadata { - Some(metadata) => { - for (k, v) in metadata { - if k == "channel" { - match v.as_str() { - "a" => { - // handle message from channel a - // [...] - - // unsubscribe from channel a - update_guest_configuration(GuestConfigurationResult { - channels: vec!["b".to_string(), "c".to_string()], - ..Default::default() - }).unwrap() - - // abandon message - consumer::abandon_message(m).unwrap(); - } - "b" => { - // handle message from channel b - // [...] - - // request-reply from channel d - let client = connect("some-broker").unwrap(); - let msgs = subscribe_try_receive(client, "d", 100).unwrap(); - - // do something with msgs - // [...] - - // disconnect client - disconnect(client); - - // complete message - consumer::complete_message(m).unwrap(); - } - "c" => { - // handle message from channel c - // [...] - - // send message to channel d - let client = connect("some-broker").unwrap(); - let message = MessageParam { - data: "hello from guest".as_bytes(), - format: messaging_types::FormatSpec::Raw, - metadata: None, - }; - producer::send(client, "d", &[message]).unwrap(); - disconnect(client); - - // complete message - consumer::complete_message(m).unwrap(); - } - _ => { - // handle message from unknown channel - } - } - } - } - } - None => { - // handle message with no metadata - } - } - } - } -} - -export_messaging!(MyGuest); -``` \ No newline at end of file diff --git a/imports-request-reply.md b/imports-request-reply.md index bc3be87..d183745 100644 --- a/imports-request-reply.md +++ b/imports-request-reply.md @@ -52,36 +52,8 @@ Kafka/EventHubs, QoS etc.).

  • channels: list<channel>
  • extensions: option<list<(string, string)>>
  • -

    record message

    -

    A message with a binary payload and additional information

    -
    Record Fields
    -
      -
    • -

      topic: channel

      -

      The topic/subject/channel this message was received or should be sent on -

    • -
    • -

      content-type: option<string>

      -

      An optional content-type describing the format of the data in the message. This is -sometimes described as the "format" type -

    • -
    • -

      reply-to: option<string>

      -

      An optional topic for use in request/response scenarios. Senders and consumers of -messages must not assume that this field is set and should handle it in their code -accordingly. -

    • -
    • -

      data: list<u8>

      -

      An opaque blob of data -

    • -
    • -

      metadata: option<list<(string, string)>>

      -

      Optional metadata (also called headers or attributes in some systems) attached to the -message -

    • -
    -
    +

    resource message

    +

    A message with a binary payload and additional information

    Functions

    [static]client.connect: func

    Params
    @@ -92,6 +64,100 @@ message +

    [constructor]message: func

    +
    Params
    +
      +
    • topic: channel
    • +
    • data: list<u8>
    • +
    • content-type: option<string>
    • +
    • metadata: option<list<(string, string)>>
    • +
    +
    Return values
    + +

    [method]message.topic: func

    +

    The topic/subject/channel this message was received or should be sent on

    +
    Params
    + +
    Return values
    + +

    [method]message.content-type: func

    +

    An optional content-type describing the format of the data in the message. This is +sometimes described as the "format" type

    +
    Params
    + +
    Return values
    +
      +
    • option<string>
    • +
    +

    [method]message.data: func

    +

    An opaque blob of data

    +
    Params
    + +
    Return values
    +
      +
    • list<u8>
    • +
    +

    [method]message.metadata: func

    +

    Optional metadata (also called headers or attributes in some systems) attached to the +message

    +
    Params
    + +
    Return values
    +
      +
    • option<list<(string, string)>>
    • +
    +

    [method]message.complete: func

    +

    Completes/acks the message

    +

    A message can exist under several statuses: +(1) available: the message is ready to be read, +(2) acquired: the message has been sent to a consumer (but still exists in the queue), +(3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, +(4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be:

    +
      +
    • deleted,
    • +
    • sent to a dead-letter queue, or
    • +
    • kept in the queue for further processing.
    • +
    +
    Params
    + +
    Return values
    + +

    [method]message.abandon: func

    +

    Abandon/nacks the message

    +

    A message can exist under several statuses: +(1) available: the message is ready to be read, +(2) acquired: the message has been sent to a consumer (but still exists in the queue), +(3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, +(4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be:

    +
      +
    • deleted,
    • +
    • sent to a dead-letter queue, or
    • +
    • kept in the queue for further processing.
    • +
    +
    Params
    + +
    Return values
    +

    Import interface wasi:messaging/request-reply@0.2.0-draft

    The request-reply interface allows a guest to send a message and await a response. This interface is considered optional as not all message services support the concept of @@ -113,21 +179,28 @@ included it as a core interface.

    request: func

    Performs a blocking request/reply operation with an optional timeout. If the timeout value is not set, then the request/reply operation will block indefinitely.

    -

    Please note that implementations that provide wasi:messaging are responsible for ensuring -that guests are not allowed to subscribe to channels that they are not configured to -subscribe to (or have access to). Failure to do so can result in possible breakout or access -to resources that are not intended to be accessible to the guest. This means implementations -should validate that the reply-to field is a valid topic the guest should have access to or -enforce it via the credentials used to connect to the service.

    Params
    Return values
    +

    reply: func

    +

    Replies to the given message with the given response message. The details of which channel +the message is sent to is up to the implementation. This allows for reply to details to be +handled in the best way possible for the underlying messaging system.

    +
    Params
    + +
    Return values
    +

    Import interface wasi:messaging/producer@0.2.0-draft

    The producer interface is used to send messages to a channel/topic.

    @@ -154,28 +227,18 @@ override the channel/topic in the message.

    Return values

    Import interface wasi:messaging/consumer@0.2.0-draft

    -

    The consumer interface allows a guest to dynamically update its subscriptions and configuration -as well as functionality for completing (acking) or abandoning (nacking) messages.

    +

    The consumer interface allows a guest to dynamically update its subscriptions and configuration


    Types

    -

    type client

    -

    client

    -

    -#### `type message` -[`message`](#message) -

    -#### `type channel` -[`channel`](#channel) -

    -#### `type error` -[`error`](#error) +

    type error

    +

    error

    #### `type guest-configuration` [`guest-configuration`](#guest_configuration) @@ -203,31 +266,3 @@ enforce it via the credentials used to connect to the service.

    -

    complete-message: func

    -

    A message can exist under several statuses: -(1) available: the message is ready to be read, -(2) acquired: the message has been sent to a consumer (but still exists in the queue), -(3) accepted (result of complete-message): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, -(4) rejected (result of abandon-message): the message has been received and NACK-ed by a consumer, at which point it can be:

    -
      -
    • deleted,
    • -
    • sent to a dead-letter queue, or
    • -
    • kept in the queue for further processing.
    • -
    -
    Params
    - -
    Return values
    - -

    abandon-message: func

    -
    Params
    - -
    Return values
    - diff --git a/imports.md b/imports.md index 1ef5346..384da07 100644 --- a/imports.md +++ b/imports.md @@ -51,36 +51,8 @@ Kafka/EventHubs, QoS etc.).

  • channels: list<channel>
  • extensions: option<list<(string, string)>>
  • -

    record message

    -

    A message with a binary payload and additional information

    -
    Record Fields
    -
      -
    • -

      topic: channel

      -

      The topic/subject/channel this message was received or should be sent on -

    • -
    • -

      content-type: option<string>

      -

      An optional content-type describing the format of the data in the message. This is -sometimes described as the "format" type -

    • -
    • -

      reply-to: option<string>

      -

      An optional topic for use in request/response scenarios. Senders and consumers of -messages must not assume that this field is set and should handle it in their code -accordingly. -

    • -
    • -

      data: list<u8>

      -

      An opaque blob of data -

    • -
    • -

      metadata: option<list<(string, string)>>

      -

      Optional metadata (also called headers or attributes in some systems) attached to the -message -

    • -
    -
    +

    resource message

    +

    A message with a binary payload and additional information

    Functions

    [static]client.connect: func

    Params
    @@ -91,6 +63,100 @@ message +

    [constructor]message: func

    +
    Params
    +
      +
    • topic: channel
    • +
    • data: list<u8>
    • +
    • content-type: option<string>
    • +
    • metadata: option<list<(string, string)>>
    • +
    +
    Return values
    + +

    [method]message.topic: func

    +

    The topic/subject/channel this message was received or should be sent on

    +
    Params
    + +
    Return values
    + +

    [method]message.content-type: func

    +

    An optional content-type describing the format of the data in the message. This is +sometimes described as the "format" type

    +
    Params
    + +
    Return values
    +
      +
    • option<string>
    • +
    +

    [method]message.data: func

    +

    An opaque blob of data

    +
    Params
    + +
    Return values
    +
      +
    • list<u8>
    • +
    +

    [method]message.metadata: func

    +

    Optional metadata (also called headers or attributes in some systems) attached to the +message

    +
    Params
    + +
    Return values
    +
      +
    • option<list<(string, string)>>
    • +
    +

    [method]message.complete: func

    +

    Completes/acks the message

    +

    A message can exist under several statuses: +(1) available: the message is ready to be read, +(2) acquired: the message has been sent to a consumer (but still exists in the queue), +(3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, +(4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be:

    +
      +
    • deleted,
    • +
    • sent to a dead-letter queue, or
    • +
    • kept in the queue for further processing.
    • +
    +
    Params
    + +
    Return values
    + +

    [method]message.abandon: func

    +

    Abandon/nacks the message

    +

    A message can exist under several statuses: +(1) available: the message is ready to be read, +(2) acquired: the message has been sent to a consumer (but still exists in the queue), +(3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, +(4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be:

    +
      +
    • deleted,
    • +
    • sent to a dead-letter queue, or
    • +
    • kept in the queue for further processing.
    • +
    +
    Params
    + +
    Return values
    +

    Import interface wasi:messaging/producer@0.2.0-draft

    The producer interface is used to send messages to a channel/topic.


    @@ -116,28 +182,18 @@ override the channel/topic in the message.

    Return values

    Import interface wasi:messaging/consumer@0.2.0-draft

    -

    The consumer interface allows a guest to dynamically update its subscriptions and configuration -as well as functionality for completing (acking) or abandoning (nacking) messages.

    +

    The consumer interface allows a guest to dynamically update its subscriptions and configuration


    Types

    -

    type client

    -

    client

    -

    -#### `type message` -[`message`](#message) -

    -#### `type channel` -[`channel`](#channel) -

    -#### `type error` -[`error`](#error) +

    type error

    +

    error

    #### `type guest-configuration` [`guest-configuration`](#guest_configuration) @@ -165,31 +221,3 @@ enforce it via the credentials used to connect to the service.

    -

    complete-message: func

    -

    A message can exist under several statuses: -(1) available: the message is ready to be read, -(2) acquired: the message has been sent to a consumer (but still exists in the queue), -(3) accepted (result of complete-message): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, -(4) rejected (result of abandon-message): the message has been received and NACK-ed by a consumer, at which point it can be:

    -
      -
    • deleted,
    • -
    • sent to a dead-letter queue, or
    • -
    • kept in the queue for further processing.
    • -
    -
    Params
    - -
    Return values
    - -

    abandon-message: func

    -
    Params
    - -
    Return values
    - diff --git a/messaging.md b/messaging.md index 9765a8e..2702f43 100644 --- a/messaging.md +++ b/messaging.md @@ -56,36 +56,8 @@ Kafka/EventHubs, QoS etc.).

  • channels: list<channel>
  • extensions: option<list<(string, string)>>
  • -

    record message

    -

    A message with a binary payload and additional information

    -
    Record Fields
    -
      -
    • -

      topic: channel

      -

      The topic/subject/channel this message was received or should be sent on -

    • -
    • -

      content-type: option<string>

      -

      An optional content-type describing the format of the data in the message. This is -sometimes described as the "format" type -

    • -
    • -

      reply-to: option<string>

      -

      An optional topic for use in request/response scenarios. Senders and consumers of -messages must not assume that this field is set and should handle it in their code -accordingly. -

    • -
    • -

      data: list<u8>

      -

      An opaque blob of data -

    • -
    • -

      metadata: option<list<(string, string)>>

      -

      Optional metadata (also called headers or attributes in some systems) attached to the -message -

    • -
    -
    +

    resource message

    +

    A message with a binary payload and additional information

    Functions

    [static]client.connect: func

    Params
    @@ -96,6 +68,100 @@ message +

    [constructor]message: func

    +
    Params
    +
      +
    • topic: channel
    • +
    • data: list<u8>
    • +
    • content-type: option<string>
    • +
    • metadata: option<list<(string, string)>>
    • +
    +
    Return values
    + +

    [method]message.topic: func

    +

    The topic/subject/channel this message was received or should be sent on

    +
    Params
    + +
    Return values
    + +

    [method]message.content-type: func

    +

    An optional content-type describing the format of the data in the message. This is +sometimes described as the "format" type

    +
    Params
    + +
    Return values
    +
      +
    • option<string>
    • +
    +

    [method]message.data: func

    +

    An opaque blob of data

    +
    Params
    + +
    Return values
    +
      +
    • list<u8>
    • +
    +

    [method]message.metadata: func

    +

    Optional metadata (also called headers or attributes in some systems) attached to the +message

    +
    Params
    + +
    Return values
    +
      +
    • option<list<(string, string)>>
    • +
    +

    [method]message.complete: func

    +

    Completes/acks the message

    +

    A message can exist under several statuses: +(1) available: the message is ready to be read, +(2) acquired: the message has been sent to a consumer (but still exists in the queue), +(3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, +(4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be:

    +
      +
    • deleted,
    • +
    • sent to a dead-letter queue, or
    • +
    • kept in the queue for further processing.
    • +
    +
    Params
    + +
    Return values
    + +

    [method]message.abandon: func

    +

    Abandon/nacks the message

    +

    A message can exist under several statuses: +(1) available: the message is ready to be read, +(2) acquired: the message has been sent to a consumer (but still exists in the queue), +(3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, +(4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be:

    +
      +
    • deleted,
    • +
    • sent to a dead-letter queue, or
    • +
    • kept in the queue for further processing.
    • +
    +
    Params
    + +
    Return values
    +

    Import interface wasi:messaging/producer@0.2.0-draft

    The producer interface is used to send messages to a channel/topic.


    @@ -121,28 +187,18 @@ override the channel/topic in the message.

    Return values

    Import interface wasi:messaging/consumer@0.2.0-draft

    -

    The consumer interface allows a guest to dynamically update its subscriptions and configuration -as well as functionality for completing (acking) or abandoning (nacking) messages.

    +

    The consumer interface allows a guest to dynamically update its subscriptions and configuration


    Types

    -

    type client

    -

    client

    -

    -#### `type message` -[`message`](#message) -

    -#### `type channel` -[`channel`](#channel) -

    -#### `type error` -[`error`](#error) +

    type error

    +

    error

    #### `type guest-configuration` [`guest-configuration`](#guest_configuration) @@ -170,34 +226,6 @@ enforce it via the credentials used to connect to the service.

    -

    complete-message: func

    -

    A message can exist under several statuses: -(1) available: the message is ready to be read, -(2) acquired: the message has been sent to a consumer (but still exists in the queue), -(3) accepted (result of complete-message): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, -(4) rejected (result of abandon-message): the message has been received and NACK-ed by a consumer, at which point it can be:

    -
      -
    • deleted,
    • -
    • sent to a dead-letter queue, or
    • -
    • kept in the queue for further processing.
    • -
    -
    Params
    - -
    Return values
    - -

    abandon-message: func

    -
    Params
    - -
    Return values
    -

    Export interface wasi:messaging/guest@0.2.0-draft


    Types

    @@ -214,10 +242,11 @@ enforce it via the credentials used to connect to the service.

    Functions

    handler: func

    Whenever this guest receives a message in one of the subscribed channels, the message is -sent to this handler

    +sent to this handler. The guest is responsible for matching on the channel and handling the +message accordingly.

    Params
    Return values
      diff --git a/wit/consumer.wit b/wit/consumer.wit index 76c105a..a229114 100644 --- a/wit/consumer.wit +++ b/wit/consumer.wit @@ -1,7 +1,6 @@ /// The consumer interface allows a guest to dynamically update its subscriptions and configuration -/// as well as functionality for completing (acking) or abandoning (nacking) messages. interface consumer { - use types.{client, message, channel, error, guest-configuration}; + use types.{error, guest-configuration}; /// 'Fit-all' type function for updating a guest's configuration – this could be useful for: /// - unsubscribing from a channel, @@ -15,15 +14,4 @@ interface consumer { /// should validate that the configured topics are valid topics the guest should have access to or /// enforce it via the credentials used to connect to the service. update-guest-configuration: func(gc: guest-configuration) -> result<_, error>; - - /// A message can exist under several statuses: - /// (1) available: the message is ready to be read, - /// (2) acquired: the message has been sent to a consumer (but still exists in the queue), - /// (3) accepted (result of complete-message): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, - /// (4) rejected (result of abandon-message): the message has been received and NACK-ed by a consumer, at which point it can be: - /// - deleted, - /// - sent to a dead-letter queue, or - /// - kept in the queue for further processing. - complete-message: func(m: message) -> result<_, error>; - abandon-message: func(m: message) -> result<_, error>; } diff --git a/wit/guest.wit b/wit/guest.wit index 9138149..b4c8eea 100644 --- a/wit/guest.wit +++ b/wit/guest.wit @@ -2,6 +2,7 @@ interface guest { use types.{message, guest-configuration, error}; /// Whenever this guest receives a message in one of the subscribed channels, the message is - /// sent to this handler - handler: func(ms: list) -> result<_, error>; + /// sent to this handler. The guest is responsible for matching on the channel and handling the + /// message accordingly. + handler: func(ms: message) -> result<_, error>; } diff --git a/wit/producer.wit b/wit/producer.wit index 99931d3..0bf388b 100644 --- a/wit/producer.wit +++ b/wit/producer.wit @@ -4,5 +4,5 @@ interface producer { /// Sends a message to the given channel/topic. If the channel/topic is not empty, it will /// override the channel/topic in the message. - send: func(c: client, ch: channel, m: list) -> result<_, error>; + send: func(c: client, ch: channel, m: message) -> result<_, error>; } diff --git a/wit/request-reply.wit b/wit/request-reply.wit index bf08022..513ea8f 100644 --- a/wit/request-reply.wit +++ b/wit/request-reply.wit @@ -7,12 +7,10 @@ interface request-reply { /// Performs a blocking request/reply operation with an optional timeout. If the timeout value /// is not set, then the request/reply operation will block indefinitely. - /// - /// Please note that implementations that provide `wasi:messaging` are responsible for ensuring - /// that guests are not allowed to subscribe to channels that they are not configured to - /// subscribe to (or have access to). Failure to do so can result in possible breakout or access - /// to resources that are not intended to be accessible to the guest. This means implementations - /// should validate that the reply-to field is a valid topic the guest should have access to or - /// enforce it via the credentials used to connect to the service. request: func(c: client, msg: message, timeout-ms: option) -> result>, error>; + + /// Replies to the given message with the given response message. The details of which channel + /// the message is sent to is up to the implementation. This allows for reply to details to be + /// handled in the best way possible for the underlying messaging system. + reply: func(reply-to: borrow, reply: message) -> result<_, error>; } \ No newline at end of file diff --git a/wit/types.wit b/wit/types.wit index 0af0012..c408f53 100644 --- a/wit/types.wit +++ b/wit/types.wit @@ -34,20 +34,41 @@ interface types { } /// A message with a binary payload and additional information - record message { + resource message { + constructor(topic: channel, data: list, content-type: option, metadata: option>>); /// The topic/subject/channel this message was received or should be sent on - topic: channel, + topic: func() -> channel; /// An optional content-type describing the format of the data in the message. This is /// sometimes described as the "format" type - content-type: option, - /// An optional topic for use in request/response scenarios. Senders and consumers of - /// messages must not assume that this field is set and should handle it in their code - /// accordingly. - reply-to: option, + content-type: func() -> option; /// An opaque blob of data - data: list, + data: func() -> list; /// Optional metadata (also called headers or attributes in some systems) attached to the /// message - metadata: option>> + metadata: func() -> option>>; + + /// Completes/acks the message + /// + /// A message can exist under several statuses: + /// (1) available: the message is ready to be read, + /// (2) acquired: the message has been sent to a consumer (but still exists in the queue), + /// (3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, + /// (4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be: + /// - deleted, + /// - sent to a dead-letter queue, or + /// - kept in the queue for further processing. + complete: func() -> result<_, error>; + + /// Abandon/nacks the message + /// + /// A message can exist under several statuses: + /// (1) available: the message is ready to be read, + /// (2) acquired: the message has been sent to a consumer (but still exists in the queue), + /// (3) accepted (result of complete): the message has been received and ACK-ed by a consumer and can be safely removed from the queue, + /// (4) rejected (result of abandon): the message has been received and NACK-ed by a consumer, at which point it can be: + /// - deleted, + /// - sent to a dead-letter queue, or + /// - kept in the queue for further processing. + abandon: func() -> result<_, error>; } } \ No newline at end of file