Book a consultation

Solace Messaging Explained: Topics, Queues and Delivery Modes

Solace Guaranteed Messaging: Queues, Acknowledgements and Spooling

Solace guaranteed messaging explained: how the message spool, publisher and consumer acknowledgements, queue access types and dead message queues work.

Vladimir Romanov


Solace guaranteed messaging is the delivery mode in which the Solace Event Broker stores every message on persistent storage, acknowledges the publisher only once it holds the message, and keeps it on a queue until the consumer acknowledges it back. Solace’s guaranteed messages page states that messages “accepted by the event broker through Guaranteed messaging for delivery to clients are never lost, but might not be accepted if system resource limits are exceeded”. That sentence holds the whole design: two acknowledgements, a store in between, and a limit someone has to plan.

This page walks the delivery path, the queue options and the failure handling. It belongs to the Solace messaging model in the Solace cluster.

The Solace guaranteed messaging delivery path

The guaranteed delivery path through a Solace queue A publisher sends a persistent message to the event broker, which stores it on a queue on the message spool and then acknowledges the publisher. The broker delivers the message to a consumer, which acknowledges after processing, and the broker then removes the message. If no acknowledgement arrives or the message is rejected, it is redelivered up to the queue's max-redelivery count and then moved to a dead message queue if it is eligible. The publisher keeps unacknowledged messages so it can resend them. Publisher MES gateway Event broker queue on the message spool stored before step 2 5 acked message removed Consumer ERP integration 1 publish 2 ack 3 deliver 4 ack No ack or rejected: redeliver up to max-redelivery, then DMQ if eligible Publisher keeps unacked messages to resend Consumer acks only after it has committed the work
The guarantee is two handovers with a store in between. Each side lets go of a message only when the next side has acknowledged it, which is why a crash anywhere leads to a resend, not a loss.
  1. Publish. The application sends the message with persistent delivery mode. The APIs allow a number of unacknowledged messages in flight, set by the publish window session property.
  2. Store and acknowledge. The broker writes the message to the spool for every matching durable endpoint and then acknowledges. Per Solace’s publisher acknowledgement page, by default it acknowledges when a third of the publish window is reached or one second has passed. If the spool quota is full, the publisher is not acknowledged, so a publisher that ignores missing acknowledgements can lose data before the broker ever had it.
  3. Deliver. The broker pushes messages to the bound consumer’s flow. Messages “are delivered in the order they were published”.
  4. Consumer acknowledgement. The consumer acknowledges each message, which, in Solace’s words, pulls “another message into its flow pipeline”. The APIs offer automatic acknowledgement and client acknowledgement; for anything important, acknowledge only after the work is committed.
  5. Remove. Once acknowledged, the message is deleted from that queue. Other queues holding the same message are unaffected.

What it means in a plant. A batch-complete event from MES reaches ERP even if ERP is down for a two-hour patch window: the queue holds it, and ERP drains the backlog when it reconnects. The price is that both ends must be written for at-least-once delivery. A consumer that crashes after posting a goods receipt but before acknowledging will see the message again, so it needs an idempotency check such as the batch ID.

Queues, topic endpoints and access types

Solace has two endpoint types, and its endpoints page is direct about which to use: queues “are significantly more flexible than topic endpoints and are the recommended approach for most applications”. Queues hold one or more topic subscriptions, including ! exceptions, so the same published event can land in several queues, one per consuming system.

Row of loading dock doors along the side of a commercial building
Each consuming system gets its own dock. A delay at one door holds up only that door's deliveries, never the others.
ChoiceOptionsBehaviourUse it for
DurabilityDurable or temporaryDurable queues survive broker restarts and are part of configuration; temporary queues last only while the client session is connectedDurable for any system of record; temporary for request-reply inboxes
Access typeExclusiveOne active consumer, others on standby; “always delivers messages in the order they are received”Ordered streams with a hot standby, such as an ERP posting service
Non-exclusiveMany consumers at once, served round-robinScaling a stateless worker pool
Non-exclusive, partitionedOrder kept per key, load shared across consumersOrdered per machine or order, at scale (partitioned queues)
SelectorsSQL92 filter, up to 2,000 bytesFilters on message properties at bind timeOccasional refinement; topics are the better filter

Exclusive versus non-exclusive is an ordering decision. Round-robin across three consumers means message 2 can finish before message 1. If that breaks your logic, use exclusive access or partition by key.

Topic endpoints exist mainly for JMS durable topic subscribers. A non-durable endpoint allows only one consumer and no non-exclusive access.

When delivery fails: redelivery, TTL and dead message queues

The queues page describes how a queue gives up on a message:

  • Max redelivery. Each queue has a max-redelivery setting. A message is removed when its redelivery attempts exceed it. A value of 0 means unlimited retries, which lets one malformed message (a “poison message”) cycle forever. Check what your queues are set to.
  • Time to live. A message can carry a TTL, and a queue configured to respect TTL removes it when it expires.
  • Dead message queue. Removed messages can go to a DMQ, by default #DEAD_MSG_QUEUE. Historically only messages published as DMQ-eligible went there. From 10.25.10, the docs state that all messages removed from the queue are sent to the endpoint’s DMQ, and 10.26.0 (the LTS as of October 2026) added endpoint-level eligibility overrides.

Set max-redelivery deliberately and watch the DMQ. A DMQ that nobody reads is a silent data-loss path with extra steps. Alert on its depth and give someone the job of draining it.

Direct messages that land on queues

If a direct (non-persistent) message matches a queue subscription, it is promoted: spooled, and from then on held until acknowledged. This lets a lightweight gateway publish direct while one consumer still gets durability. The reverse, demotion of persistent messages to a direct subscriber, gives no guarantee and can produce duplicates. The broader trade-off between the two modes is on the messaging model page.

Designing a plant flow with Solace guaranteed messaging

An illustrative example. MES publishes mfg/batch/completed/v1/{site}/{area}/{unit}/- when a batch closes. Three systems need it: ERP for goods receipt, the quality system for release, and a data platform for analytics. A workable design:

  1. One durable queue per consuming system, each subscribed to mfg/batch/completed/v1/>. ERP’s outage then never delays quality release.
  2. Exclusive access for ERP, with a standby instance bound. Postings stay in order and a failed instance hands over without a gap.
  3. Non-exclusive access for analytics, where order does not matter and three workers share the load.
  4. Max-redelivery set to a small number, such as five, with a DMQ per system so a malformed batch record is parked, alerted on and fixed rather than retried forever.
  5. Idempotent consumers keyed on batch ID, so a redelivered message is recognised and skipped.
  6. A quota sized for the longest planned outage, for example a weekend ERP upgrade at peak batch rate, plus margin.

The same pattern applies to production orders flowing down to a line, quality results flowing up, and genealogy records feeding traceability.

Where it gets hard

  • Spool sizing. A queue fills when its consumer is down. Size the quota for the longest outage you will tolerate times the peak rate, and alert well before full. The free Standard Edition caps the spool at 800 GB and is marked not production deployable.
  • Slow consumers. A queue hides a consumer that cannot keep up until the backlog is large. Monitor queue depth and age, not only connection state.
  • Duplicates are normal. Failover, reconnects and redelivery all produce them. Design every consumer to be idempotent.
  • MQTT QoS mapping. MQTT QoS 1 maps to guaranteed delivery, but QoS 2 is downgraded to QoS 1, per Solace’s MQTT documentation. Exactly-once is not on offer.
  • HA and DR change the picture. What happens to in-flight messages on failover and under asynchronous replication is covered on high availability and disaster recovery.

Related: message replay for re-reading history after the queue has delivered it, and our IT/OT integration service for deciding which plant flows need this guarantee.

Frequently asked questions

How does Solace guaranteed messaging prevent message loss?

The broker writes each guaranteed message to its message spool, which is persistent storage, before acknowledging the publisher. It then keeps the message on every matching durable endpoint until each consumer acknowledges it. Solace states that messages accepted this way are never lost, though the broker can refuse new messages when spool limits are reached, so the publisher must handle a missing acknowledgement.

What is the difference between an exclusive and a non-exclusive queue in Solace?

On an exclusive queue only one consumer is active at a time; others bind as standbys and take over if it leaves, and messages are delivered in the order received. On a non-exclusive queue many consumers bind at once and the broker shares messages among them round-robin, which scales throughput but gives up strict ordering unless the queue is partitioned.

What is a dead message queue in Solace?

A dead message queue (DMQ) receives messages a queue gives up on, for example when the redelivery count exceeds the queue's max-redelivery setting or a message's time-to-live expires on an endpoint that respects TTL. The default name is #DEAD_MSG_QUEUE. Which messages qualify has changed across releases, so check the behaviour for the broker version you run.

Should I use queues or topic endpoints in Solace?

Use queues. Solace's documentation states that queues are significantly more flexible than topic endpoints and are the recommended approach for most applications. Queues accept several topic subscriptions, exceptions and many consumers. Topic endpoints exist mainly to support JMS durable topic subscribers, which some older Java applications still expect.

What happens if a consumer crashes before acknowledging a message?

The message stays on the queue, because the broker deletes it only after an acknowledgement. When the consumer, or another consumer on the queue, binds again, the message is redelivered and marked as redelivered. That is at-least-once delivery, so the consuming application should be able to recognise and ignore a message it already processed.

References and further reading

  1. Guaranteed Messages · SolaceThe guarantee, spooling and ordering, in Solace's words.
  2. Queues · SolaceAccess types, redelivery, dead message queues and last value queues.
  3. Endpoints · Solace
  4. Acknowledging Published Guaranteed Messages · SolaceThe publish window and when the broker acknowledges.
  5. Message Promotion and Demotion · Solace

← Messaging Model

Have a project that needs technical ownership?

Send us the situation. If it is not something we should take on, we will say so.