Delivery Semantics

The Internet, as well as other networks, is considered an unreliable communication channel. There can be delays or lost messages, and connections can fail unexpectedly. This affects the reliability of record delivery between producers and the SPU.

Fluvio producers can be configued with a delivery_semantic configuration option, which allows choosing a delivery mechanism. Each mechanism has a different trade-off between reliability and performance. There are two delivery semantics currently supported by producers: at-most-once and at-least-once (default).

Regardless of delivery_semantic, Fluvio batches outgoing records so it is necessary to flush the producer once all records have been sent to ensure proper delivery.

let fluvio = Fluvio::connect().await?;
let config = TopicProducerConfigBuilder::default()
    .delivery_semantic(DeliverySemantic::AtMostOnce)
    .build()?;
let producer = fluvio.topic_producer_with_config("greetings", config).await?;
producer.send("Hello", "Fluvio!").await?;
producer.flush().await?;

The mechanism for accessing response metadata for produced records is also the same for both at-most-once and at-least-once delivery semantics.

let output = producer.send("Hello", "Fluvio!").await?;
// Provides response metadata for records such as offset.
// This only returns once batch has been sent and ack is received from SPU.
output.wait().await?; 
 

At Most Once

at-most-once delivery means that for each record generated by a producer, that record is delivered zero or one times. This means that messages may be lost.

The producer sends the message with records to the SPU and does not wait for the response. This delivery method has higher throughput but no guarantees that the message was delivered.

Producer Isolation has no effect if this delivery semantic is used unless the user explicitly waits for the response, as shown in the following snippet:

let fluvio = Fluvio::connect().await?;
let config = TopicProducerConfigBuilder::default()
    .delivery_semantic(DeliverySemantic::AtMostOnce)
    .build()?;
let producer = fluvio.topic_producer_with_config("greetings", config).await?;
let output = producer.send("Hello", "Fluvio!").await?;
output.wait().await?; // Producer isolation has no effect unless wait() is called
 

At Least Once

at-least-once delivery means that for each record handed to the producer potentially multiple attempts are made at delivering it, such that at least one succeeds. This means that messages may be duplicated but not lost.

The producer sends the message with records to the SPU, waits for the response and resends in case of transport errors occur. This delivery method has lower throughput comparing to at-most-once but better reliability.

Producer Isolation determines when the SPU will send the response signifying a successful delivery.

There are three main parameters that can be configured for at-least-once semantic: maximum amount of retries, the retry backoff strategy (fixed, Fibonacci, or exponential), and maximum timeout for all attempts.

Example:

let policy = RetryPolicy {
    max_retries: 5,
    initial_delay: Duration::from_millis(10),
    max_delay: Duration::from_sec(2),
    timeout: Duration::from_sec(10),
    strategy: RetryStrategy::ExponentialBackoff
};
let config = TopicProducerConfigBuilder::default()
    .delivery_semantic(DeliverySemantic::AtLeastOnce(policy))
    .build()?;
let producer = fluvio.topic_producer_with_config("greetings", config).await?;

In the above example, Fluvio Producer retries at most five times; all retries take a maximum of 10 seconds. The delay between retries increases exponentially. The first delay is 10ms, the second is 100ms, then 1000ms, and all others are 2000ms as it’s defined as a maximum allowed delay.