Interface Publisher<T>

Type Parameters:
T - payload type
All Superinterfaces:
AutoCloseable
All Known Implementing Classes:
DefaultPublisher

public interface Publisher<T> extends AutoCloseable
Sends messages of one type to one destination.

Publishers are thread safe and meant to be long lived: build one per message type at startup and reuse it.

  • Method Details

    • send

      PublishResult send(T payload)
      Publishes a message and waits for the broker to confirm it.
      Parameters:
      payload - the payload to send
      Returns:
      the confirmed result
      Throws:
      PublishFailedException - if the broker rejected the message, could not route it, or did not confirm in time
    • send

      PublishResult send(T payload, Envelope envelope)
      Publishes a message built on an explicit envelope.

      Used when correlation or causation must be carried from a message being handled, so that a whole flow can be followed in traces and logs.

      Parameters:
      payload - the payload to send
      envelope - metadata to publish it with
      Returns:
      the confirmed result
      Throws:
      PublishFailedException - as for send(Object)
    • sendAsync

      CompletableFuture<PublishResult> sendAsync(T payload)
      Publishes without waiting for the broker to confirm.

      A synchronous publish costs a round trip per message, so a loop over ten thousand of them spends nearly all its time waiting. This lets the next message go out while the last is still in flight, and is typically an order of magnitude faster for bulk work.

      Nothing about the guarantees changes: the future carries the same result send(Object) returns, and fails the same way — including when nothing was bound to receive the message. What changes is when you find out.

      A future nobody waits on is a message nobody knows the fate of. That is the failure this library exists to prevent, so somebody has to check, eventually. If you do not intend to look at the result, use send(Object) and take the round trip.

      
       List<CompletableFuture<PublishResult>> inFlight = new ArrayList<>();
       for (Order order : thousands) {
           inFlight.add(publisher.sendAsync(order));
       }
       CompletableFuture.allOf(inFlight.toArray(new CompletableFuture[0])).join();
       

      Publishing blocks once too many messages are awaiting confirmation, which is deliberate: an asynchronous publisher with no ceiling is a memory leak that looks like throughput.

      Parameters:
      payload - the payload to send
      Returns:
      a future completed with the broker's answer, or failed as send(Object) would have thrown
    • sendAsync

      CompletableFuture<PublishResult> sendAsync(T payload, Envelope envelope)
      Publishes without waiting, with an envelope of your own.
      Parameters:
      payload - the payload to send
      envelope - identity, correlation and headers to travel with it
      Returns:
      a future completed with the broker's answer
    • sendAll

      List<PublishResult> sendAll(Collection<? extends T> payloads)
      Publishes a batch and waits for every confirm.

      What most bulk publishing actually wants: the throughput of pipelining with the safety of having waited. Every message goes out before any confirm is awaited, then all of them are checked together.

      Fails if any message failed, and the exception names how many succeeded — a partial batch is the normal outcome of a broker problem halfway through, and pretending otherwise would leave the caller resending messages that already arrived.

      This is not atomic. AMQP has no such thing: there is no way to publish a hundred messages such that all or none arrive, and a library that offered one would be lying.

      Parameters:
      payloads - the payloads to send, in order
      Returns:
      the results, in the same order
      Throws:
      PublishFailedException - if any message was not confirmed
    • close

      void close()
      Specified by:
      close in interface AutoCloseable