Interface DurableQueues
- All Superinterfaces:
Lifecycle
DurableQueues concept supports intra-service point-to-point messaging using durable Queues that guarantee At-Least-Once delivery of messages.The only requirement is that message producers and message consumers can access the same underlying durable Queue storage.
In a service oriented architecture it's common for all deployed instances of a given service (e.g. a Sales service) to share the same underlying
database(s). As long as the different deployed (Sales) services instances can share the same underlying database, then you use the DurableQueues concept for point to point messaging across all deployed (Sales service)
instances in the cluster.
If you need cross-service point to point messaging support, e.g. across instances of different services (such as across Sales, Billing and Shipping services), then you need to use a dedicated distributed Queueing service such as RabbitMQ.
This library focuses on providing a Durable Queue supporting message redelivery and Dead Letter Message functionality
and comes in two flavours PostgresqlDurableQueues and MongoDurableQueues which both implement the DurableQueues interface.
Durable Queue concept that supports queuing a message on to a named Queue. Each message is associated with a unique QueueEntryId
Each Queue is uniquely identified by its QueueName
Queued messages can, per Queue, asynchronously be consumed by a QueuedMessageHandler, by registering it as a DurableQueueConsumer using
consumeFromQueue(QueueName, RedeliveryPolicy, int, QueuedMessageHandler)
The Durable Queue concept supports competing consumers guaranteeing that a message is only consumed by one message handler at a time
The DurableQueueConsumer supports retrying failed messages, according to the specified RedeliveryPolicy, and ultimately marking a repeatedly failing message
as a Poison-Message/Dead-Letter-Message.
The RedeliveryPolicy supports fixed, linear and exponential backoff strategies.
The DurableQueues supports delayed message delivery as well as Poison-Message/Dead-Letter-Messages, which are messages that have repeatedly failed processing.
Poison Messages/Dead-Letter-Messages won't be delivered to a DurableQueueConsumer, unless they're explicitly resurrected call resurrectDeadLetterMessage(QueueEntryId, Duration)
Ordered Messages
If you're queuing with OrderedMessage then, IF and only IF, only a single cluster node is consuming from the Queue,
such as with an Inbox or Outbox configured with MessageConsumptionMode.SingleGlobalConsumer (which uses a FencedLock to
coordinate message consumption across cluster nodes)
in order to be able to guarantee that OrderedMessage's are delivered in OrderedMessage.getOrder() per
OrderedMessage.getKey() across as many parallel message consumers as you wish to use.
-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptionbooleanMark the message as acknowledged - this operation also deletes the messages from the Queue
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault booleanacknowledgeMessageAsHandled(QueueEntryId queueEntryId) Mark the message as acknowledged - this operation deletes the messages from the Queue
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaladdInterceptor(DurableQueuesInterceptor interceptor) Add aDurableQueuesInterceptorto thisDurableQueuesinstance
TheDurableQueuesInterceptorallows you to intercept all high level operationsdefault DurableQueuesaddInterceptors(List<DurableQueuesInterceptor> interceptors) AddDurableQueuesInterceptor's to thisDurableQueuesinstance
TheDurableQueuesInterceptorallows you to intercept all high level operationsconsumeFromQueue(ConsumeFromQueue operation) Start an asynchronous message consumer.
Note: There can only be oneDurableQueueConsumerperQueueNameperDurableQueuesinstance
Log levels of interest:default DurableQueueConsumerconsumeFromQueue(QueueName queueName, RedeliveryPolicy redeliveryPolicy, int parallelConsumers, QueuedMessageHandler queueMessageHandler) Start an asynchronous message consumer.
Note: There can only be oneDurableQueueConsumerperQueueNameperDurableQueuesinstance
Log levels of interest:default DurableQueueConsumerconsumeFromQueue(String consumerName, QueueName queueName, RedeliveryPolicy redeliveryPolicy, int parallelConsumers, QueuedMessageHandler queueMessageHandler) Start an asynchronous message consumer.
Note: There can only be oneDurableQueueConsumerperQueueNameperDurableQueuesinstance
Log levels of interest:booleandeleteMessage(DeleteMessage operation) Delete a message (Queued or Dead Letter Message)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault booleandeleteMessage(QueueEntryId queueEntryId) Delete a message (Queued or Dead Letter Message)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionalgetDeadLetterMessage(GetDeadLetterMessage operation) Get a queued message that's marked as aQueuedMessage.isDeadLetterMessage()default Optional<QueuedMessage>getDeadLetterMessage(QueueEntryId queueEntryId) Get a queued message that's marked as aQueuedMessage.isDeadLetterMessage()getDeadLetterMessages(GetDeadLetterMessages operation) Query Dead Letter Messages (i.e.default List<QueuedMessage>getDeadLetterMessages(QueueName queueName, DurableQueues.QueueingSortOrder queueingSortOrder, long startIndex, long pageSize) Query Dead Letter Messages (i.e.Query the next Queued Message (i.e.default Optional<QueuedMessage>getNextMessageReadyForDelivery(QueueName queueName) Query the next Queued Message (i.e.getQueuedMessage(GetQueuedMessage operation) Get a queued message that is NOT marked as aQueuedMessage.isDeadLetterMessage()default Optional<QueuedMessage>getQueuedMessage(QueueEntryId queueEntryId) Get a queued message that is NOT marked as aQueuedMessage.isDeadLetterMessage()getQueuedMessages(GetQueuedMessages operation) Query Queued Messages (i.e.default List<QueuedMessage>getQueuedMessages(QueueName queueName, DurableQueues.QueueingSortOrder queueingSortOrder, long startIndex, long pageSize) Query Queued Messages (i.e.getQueueNameFor(QueueEntryId queueEntryId) Get the name of the Queue where the message withqueueEntryIdis queued (either as a normal queued messages or a dead-letter/poison-message)Get all theQueueName's with messages queued, dead-letter-messages/poison-messages queued or which has an active queue consumerlongGet the total number of dead-letter-messages/poison-messages queued for the given queuedefault longgetTotalDeadLetterMessagesQueuedFor(QueueName queueName) Get the total number of dead-letter-messages/poison-messages queued for the given queuelongGet the total number of messages queued (i.e.default longgetTotalMessagesQueuedFor(QueueName queueName) Get the total number of messages queued (i.e.The transactional behaviour mode of thisDurableQueuesinstanceOptional<UnitOfWorkFactory<? extends UnitOfWork>>booleanhasMessagesQueuedFor(QueueName queueName) Check if there are any messages queued (i.e.markAsDeadLetterMessage(MarkAsDeadLetterMessage operation) Mark an already Queued Message as a Dead Letter Message (or Poison Message).
Dead Letter Messages won't be delivered to anyDurableQueueConsumer(called by theDurableQueueConsumer)
To deliver a Dead Letter Message you must first resurrect the message usingresurrectDeadLetterMessage(QueueEntryId, Duration)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault Optional<QueuedMessage>markAsDeadLetterMessage(QueueEntryId queueEntryId, Exception causeForBeingMarkedAsDeadLetter) Mark an already Queued Message as a Dead Letter Message (or Poison Message).
Dead Letter Messages won't be delivered to anyDurableQueueConsumer(called by theDurableQueueConsumer)
To deliver a Dead Letter Message you must first resurrect the message usingresurrectDeadLetterMessage(QueueEntryId, Duration)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionalintpurgeQueue(PurgeQueue operation) Delete all messages (Queued or Dead letter Messages) in the given queuedefault intpurgeQueue(QueueName queueName) Delete all messages (Queued or Dead letter Messages) in the given queuedefault List<NextQueuedMessage>queryForMessagesSoonReadyForDelivery(QueueName queueName, int maxNumberOfMessagesToReturn) Query for the nextmaxNumberOfMessagesToReturnqueued messages that are soon ready to be delivered usingInstant.now()aswithNextDeliveryTimestampAfter
This is a useful method for a custom queue consumer to know if it's necessary to callgetNextMessageReadyForDelivery(GetNextMessageReadyForDelivery)queryForMessagesSoonReadyForDelivery(QueueName queueName, Instant withNextDeliveryTimestampAfter, int maxNumberOfMessagesToReturn) Query for the nextmaxNumberOfMessagesToReturnqueued messages that are soon ready to be delivered
This is a useful method for a custom queue consumer to know if it's necessary to callgetNextMessageReadyForDelivery(GetNextMessageReadyForDelivery)queueMessage(QueueMessage operation) Queue a message for asynchronous delivery without delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault QueueEntryIdqueueMessage(QueueName queueName, Message message) Queue a message for asynchronous delivery without delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault QueueEntryIdqueueMessage(QueueName queueName, Message message, Exception causeOfEnqueuing, Duration deliveryDelay) Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault QueueEntryIdqueueMessage(QueueName queueName, Message message, Duration deliveryDelay) Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault QueueEntryIdqueueMessage(QueueName queueName, Message message, Optional<Exception> causeOfEnqueuing, Optional<Duration> deliveryDelay) Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault QueueEntryIdqueueMessage(QueueName queueName, Message message, Optional<Duration> deliveryDelay) Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionalQueue the message directly as a Dead Letter Message.default QueueEntryIdqueueMessageAsDeadLetterMessage(QueueName queueName, Message message, Exception causeOfError) Queue the message directly as a Dead Letter Message.queueMessages(QueueMessages operation) Queue multiple messages to the same queue.default List<QueueEntryId>queueMessages(QueueName queueName, List<? extends Message> messages) Queue multiple messages to the same queue.default List<QueueEntryId>queueMessages(QueueName queueName, List<? extends Message> messages, Duration deliveryDelay) Queue multiple messages to the same queue.default List<QueueEntryId>queueMessages(QueueName queueName, List<? extends Message> messages, Optional<Duration> deliveryDelay) Queue multiple messages to the same queue.removeInterceptor(DurableQueuesInterceptor interceptor) Resurrect a Dead Letter Message for redelivery after the specifieddeliveryDelay
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault Optional<QueuedMessage>resurrectDeadLetterMessage(QueueEntryId queueEntryId, Duration deliveryDelay) Resurrect a Dead Letter Message for redelivery after the specifieddeliveryDelay
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionalretryMessage(RetryMessage operation) Schedule the message for redelivery after the specifieddeliveryDelay(called by theDurableQueueConsumer)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionaldefault Optional<QueuedMessage>retryMessage(QueueEntryId queueEntryId, Exception causeForRetry, Duration deliveryDelay) Schedule the message for redelivery after the specifieddeliveryDelay(called by theDurableQueueConsumer)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional
-
Method Details
-
getQueueNames
Get all theQueueName's with messages queued, dead-letter-messages/poison-messages queued or which has an active queue consumer- Returns:
- all the
QueueName's with messages queued, dead-letter-messages/poison-messages queued or which has an active queue consumer
-
addInterceptor
Add aDurableQueuesInterceptorto thisDurableQueuesinstance
TheDurableQueuesInterceptorallows you to intercept all high level operations- Parameters:
interceptor- the interceptor to add- Returns:
- this
DurableQueuesinstance
-
addInterceptors
AddDurableQueuesInterceptor's to thisDurableQueuesinstance
TheDurableQueuesInterceptorallows you to intercept all high level operations- Parameters:
interceptors- the interceptors to add- Returns:
- this
DurableQueuesinstance
-
removeInterceptor
- Parameters:
interceptor- the interceptor to remove- Returns:
- this
DurableQueuesinstance
-
getQueueNameFor
Get the name of the Queue where the message withqueueEntryIdis queued (either as a normal queued messages or a dead-letter/poison-message)- Parameters:
queueEntryId- the queue entry id of the message we want to know theQueueNamefor- Returns:
- The
QueueNamewrapped in anOptionalifDurableQueuescontains a normal queued messages or a dead-letter/poison-message; otherwise anOptional.empty()
-
getDeadLetterMessage
Get a queued message that's marked as aQueuedMessage.isDeadLetterMessage()- Parameters:
queueEntryId- the messages unique queue entry id- Returns:
- the message wrapped in an
Optionalif the message exists andQueuedMessage.isDeadLetterMessage(), otherwiseOptional.empty()
-
getDeadLetterMessage
Get a queued message that's marked as aQueuedMessage.isDeadLetterMessage()- Parameters:
operation- theGetDeadLetterMessageoperation- Returns:
- the message wrapped in an
Optionalif the message exists andQueuedMessage.isDeadLetterMessage(), otherwiseOptional.empty()
-
getQueuedMessage
Get a queued message that is NOT marked as aQueuedMessage.isDeadLetterMessage()- Parameters:
queueEntryId- the messages unique queue entry id- Returns:
- the message wrapped in an
Optionalif the message exists and NOT aQueuedMessage.isDeadLetterMessage(), otherwiseOptional.empty()
-
getQueuedMessage
Get a queued message that is NOT marked as aQueuedMessage.isDeadLetterMessage()- Parameters:
operation- theGetQueuedMessageoperation- Returns:
- the message wrapped in an
Optionalif the message exists and NOT aQueuedMessage.isDeadLetterMessage(), otherwiseOptional.empty()
-
getTransactionalMode
TransactionalMode getTransactionalMode()The transactional behaviour mode of thisDurableQueuesinstance- Returns:
- The transactional behaviour mode of a
DurableQueuesinstance
-
getUnitOfWorkFactory
Optional<UnitOfWorkFactory<? extends UnitOfWork>> getUnitOfWorkFactory()- Returns:
- If
getTransactionalMode()isTransactionalMode.FullyTransactionalthen it will return theUnitOfWorkFactorywrapped in anOptional, otherwise it will return anOptional.empty()
-
consumeFromQueue
default DurableQueueConsumer consumeFromQueue(String consumerName, QueueName queueName, RedeliveryPolicy redeliveryPolicy, int parallelConsumers, QueuedMessageHandler queueMessageHandler) Start an asynchronous message consumer.
Note: There can only be oneDurableQueueConsumerperQueueNameperDurableQueuesinstance
Log levels of interest:dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer.MessageHandlingFailures- Parameters:
consumerName- the name of the consumer (for logging purposes)queueName- the name of the queue that the consumer will be listening for queued messages ready to be delivered to theQueuedMessageHandlerprovidedredeliveryPolicy- the redelivery policy in case the handling of a message failsparallelConsumers- the number of parallel consumers (if number > 1 then you will effectively have competing consumers on the current node)queueMessageHandler- the message handler that will receiveQueuedMessage's. SeePatternMatchingQueuedMessageHandler- Returns:
- the queue consumer
-
consumeFromQueue
default DurableQueueConsumer consumeFromQueue(QueueName queueName, RedeliveryPolicy redeliveryPolicy, int parallelConsumers, QueuedMessageHandler queueMessageHandler) Start an asynchronous message consumer.
Note: There can only be oneDurableQueueConsumerperQueueNameperDurableQueuesinstance
Log levels of interest:dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer.MessageHandlingFailures- Parameters:
queueName- the name of the queue that the consumer will be listening for queued messages ready to be delivered to theQueuedMessageHandlerprovidedredeliveryPolicy- the redelivery policy in case the handling of a message failsparallelConsumers- the number of parallel consumers (if number > 1 then you will effectively have competing consumers on the current node)queueMessageHandler- the message handler that will receiveQueuedMessage's. SeePatternMatchingQueuedMessageHandler- Returns:
- the queue consumer
-
consumeFromQueue
Start an asynchronous message consumer.
Note: There can only be oneDurableQueueConsumerperQueueNameperDurableQueuesinstance
Log levels of interest:dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer.MessageHandlingFailures- Parameters:
operation- TheConsumeFromQueueoperation- Returns:
- the queue consumer
-
queueMessage
Queue a message for asynchronous delivery without delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the message is added tomessage- the message- Returns:
- the unique entry id for the message queued
-
queueMessage
Queue a message for asynchronous delivery without delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
operation- theQueueMessageoperation- Returns:
- the unique entry id for the message queued
-
queueMessage
default QueueEntryId queueMessage(QueueName queueName, Message message, Optional<Duration> deliveryDelay) Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the message is added tomessage- the message (Message/OrderedMessage)deliveryDelay- Optional delay for the first delivery of the message to theDurableQueueConsumer- Returns:
- the unique entry id for the message queued
- See Also:
-
queueMessage
Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the message is added tomessage- the message (Message/OrderedMessage)deliveryDelay- Optional delay for the first delivery of the message to theDurableQueueConsumer- Returns:
- the unique entry id for the message queued
- See Also:
-
queueMessage
default QueueEntryId queueMessage(QueueName queueName, Message message, Optional<Exception> causeOfEnqueuing, Optional<Duration> deliveryDelay) Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the message is added tomessage- the message (Message/OrderedMessage)causeOfEnqueuing- the optional reason for the message being queueddeliveryDelay- Optional delay for the first delivery of the message to theDurableQueueConsumer- Returns:
- the unique entry id for the message queued
- See Also:
-
queueMessage
default QueueEntryId queueMessage(QueueName queueName, Message message, Exception causeOfEnqueuing, Duration deliveryDelay) Queue a message for asynchronous delivery optional delay to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the message is added tomessage- the message payload (Message/OrderedMessage)causeOfEnqueuing- the optional reason for the message being queueddeliveryDelay- Optional delay for the first delivery of the message to theDurableQueueConsumer- Returns:
- the unique entry id for the message queued
- See Also:
-
queueMessageAsDeadLetterMessage
default QueueEntryId queueMessageAsDeadLetterMessage(QueueName queueName, Message message, Exception causeOfError) Queue the message directly as a Dead Letter Message. Dead Letter Messages won't be delivered to anyDurableQueueConsumer
To deliver a Dead Letter Message you must first resurrect the message usingresurrectDeadLetterMessage(QueueEntryId, Duration)- Parameters:
queueName- the name of the Queue the message is added tomessage- the message (Message/OrderedMessage)causeOfError- the reason for the message being queued directly as a Dead Letter Message- Returns:
- the unique entry id for the message queued
- See Also:
-
queueMessageAsDeadLetterMessage
Queue the message directly as a Dead Letter Message. Dead Letter Messages won't be delivered to anyDurableQueueConsumer
To deliver a Dead Letter Message you must first resurrect the message usingresurrectDeadLetterMessage(QueueEntryId, Duration)- Parameters:
operation- theQueueMessageAsDeadLetterMessageoperation- Returns:
- the unique entry id for the message queued
-
queueMessages
default List<QueueEntryId> queueMessages(QueueName queueName, List<? extends Message> messages, Optional<Duration> deliveryDelay) Queue multiple messages to the same queue. All the messages will receive the sameQueuedMessage.getNextDeliveryTimestamp()
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the messages will be added tomessages- the message to enqueue (Message/OrderedMessage)deliveryDelay- optional: how long will the queue wait until it delivers the messages to theDurableQueueConsumer- Returns:
- the unique entry id's for the messages queued ordered in the same order as the payloads that were queued
-
queueMessages
default List<QueueEntryId> queueMessages(QueueName queueName, List<? extends Message> messages, Duration deliveryDelay) Queue multiple messages to the same queue. All the messages will receive the sameQueuedMessage.getNextDeliveryTimestamp()
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the messages will be added tomessages- the messages to enqueue (Message/OrderedMessage)deliveryDelay- optional: how long will the queue wait until it delivers the messages to theDurableQueueConsumer- Returns:
- the unique entry id's for the messages queued ordered in the same order as the payloads that were queued
-
queueMessages
Queue multiple messages to the same queue. All the messages will receive the sameQueuedMessage.getNextDeliveryTimestamp()
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue the messages will be added tomessages- the message to enqueue (Message/OrderedMessage)- Returns:
- the unique entry id's for the messages queued, ordered in the same order as the payloads that were queued
-
queueMessages
Queue multiple messages to the same queue. All the messages will receive the sameQueuedMessage.getNextDeliveryTimestamp()
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
operation- TheQueueMessagesoperation- Returns:
- the unique entry id's for the messages queued ordered in the same order as the payloads that were queued
-
retryMessage
default Optional<QueuedMessage> retryMessage(QueueEntryId queueEntryId, Exception causeForRetry, Duration deliveryDelay) Schedule the message for redelivery after the specifieddeliveryDelay(called by theDurableQueueConsumer)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueEntryId- the unique id of the message that must we will retry the delivery ofcauseForRetry- the reason why the message delivery has to be retrieddeliveryDelay- how long will the queue wait until it delivers the message to theDurableQueueConsumer- Returns:
- the
QueuedMessagemessage wrapped in anOptionalif the operation was successful, otherwise it returns anOptional.empty()
-
retryMessage
Schedule the message for redelivery after the specifieddeliveryDelay(called by theDurableQueueConsumer)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
operation- theRetryMessageoperation- Returns:
- the
QueuedMessagemessage wrapped in anOptionalif the operation was successful, otherwise it returns anOptional.empty()
-
markAsDeadLetterMessage
default Optional<QueuedMessage> markAsDeadLetterMessage(QueueEntryId queueEntryId, Exception causeForBeingMarkedAsDeadLetter) Mark an already Queued Message as a Dead Letter Message (or Poison Message).
Dead Letter Messages won't be delivered to anyDurableQueueConsumer(called by theDurableQueueConsumer)
To deliver a Dead Letter Message you must first resurrect the message usingresurrectDeadLetterMessage(QueueEntryId, Duration)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueEntryId- the unique id of the message that must be marked as a Dead Letter MessagecauseForBeingMarkedAsDeadLetter- the reason for the message being marked as a Dead Letter Message- Returns:
- the
QueuedMessagemessage wrapped in anOptionalif the operation was successful, otherwise it returns anOptional.empty()
-
markAsDeadLetterMessage
Mark an already Queued Message as a Dead Letter Message (or Poison Message).
Dead Letter Messages won't be delivered to anyDurableQueueConsumer(called by theDurableQueueConsumer)
To deliver a Dead Letter Message you must first resurrect the message usingresurrectDeadLetterMessage(QueueEntryId, Duration)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
operation- theMarkAsDeadLetterMessageoperation- Returns:
- the
QueuedMessagemessage wrapped in anOptionalif the operation was successful, otherwise it returns anOptional.empty()
-
resurrectDeadLetterMessage
default Optional<QueuedMessage> resurrectDeadLetterMessage(QueueEntryId queueEntryId, Duration deliveryDelay) Resurrect a Dead Letter Message for redelivery after the specifieddeliveryDelay
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueEntryId- the unique id of the Dead Letter Message that must we will retry the delivery ofdeliveryDelay- how long will the queue wait until it delivers the message to theDurableQueueConsumer- Returns:
- the
QueuedMessagemessage wrapped in anOptionalif the operation was successful, otherwise it returns anOptional.empty()
-
resurrectDeadLetterMessage
Resurrect a Dead Letter Message for redelivery after the specifieddeliveryDelay
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
operation- theResurrectDeadLetterMessageoperation- Returns:
- the
QueuedMessagemessage wrapped in anOptionalif the operation was successful, otherwise it returns anOptional.empty()
-
acknowledgeMessageAsHandled
Mark the message as acknowledged - this operation deletes the messages from the Queue
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueEntryId- the unique id of the Message to acknowledge- Returns:
- true if the operation went well, otherwise false
-
acknowledgeMessageAsHandled
Mark the message as acknowledged - this operation also deletes the messages from the Queue
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
operation- theAcknowledgeMessageAsHandledoperation- Returns:
- true if the operation went well, otherwise false
-
deleteMessage
Delete a message (Queued or Dead Letter Message)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueEntryId- the unique id of the Message to delete- Returns:
- true if the operation went well, otherwise false
-
deleteMessage
Delete a message (Queued or Dead Letter Message)
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
operation- theDeleteMessageoperation- Returns:
- true if the operation went well, otherwise false
-
getNextMessageReadyForDelivery
Query the next Queued Message (i.e. not including Dead Letter Messages) that's ready to be delivered to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactional- Parameters:
queueName- the name of the Queue where we will query for the next message ready for delivery- Returns:
- the next message ready to be delivered (wrapped in an
Optional) orOptional.empty()if no message is ready for delivery
-
getNextMessageReadyForDelivery
Query the next Queued Message (i.e. not including Dead Letter Messages) that's ready to be delivered to aDurableQueueConsumer
Note this method MUST be called within an existingUnitOfWorkIF usingTransactionalMode.FullyTransactionalThe normal message processing flow looks like this:
durableQueues.queueMessage(queueName, message); var msgUnderDelivery = durableQueues.getNextMessageReadyForDelivery(queueName); if (msgUnderDelivery.isPresent()) { try { handleMessage(msgUnderDelivery.get()); durableQueues.acknowledgeMessageAsHandled(msgUnderDelivery.get().getId()); } catch (Exception e) { durableQueues.retryMessage(msgUnderDelivery.get().getId(), e, Duration.ofMillis(500)); } }When using
TransactionalMode.SingleOperationTransactionthen depending on the type of errors that can occur this MAY leave a dequeued message in a state of being marked as "being delivered" forever
This is whyDurableQueuessupporting these modes must ensure that they periodically discover messages that have been under delivery for a long time (aka. stuck messages or timed-out messages) and reset them in order for them to be redelivered.- Parameters:
operation- theGetNextMessageReadyForDeliveryoperation- Returns:
- the next message ready to be delivered (wrapped in an
Optional) orOptional.empty()if no message is ready for delivery
-
hasMessagesQueuedFor
Check if there are any messages queued (i.e. not including Dead Letter Messages) for the given queue- Parameters:
queueName- the name of the Queue where we will query for queued messages- Returns:
- true if there are messages queued on the given queue, otherwise false
-
getTotalMessagesQueuedFor
Get the total number of messages queued (i.e. not including Dead Letter Messages) for the given queue- Parameters:
queueName- the name of the Queue where we will query for the number of queued messages- Returns:
- the number of queued messages for the given queue
-
getTotalMessagesQueuedFor
Get the total number of messages queued (i.e. not including Dead Letter Messages) for the given queue- Parameters:
operation- theGetTotalMessagesQueuedForoperation- Returns:
- the number of queued messages for the given queue
-
getTotalDeadLetterMessagesQueuedFor
Get the total number of dead-letter-messages/poison-messages queued for the given queue- Parameters:
queueName- the name of the Queue where we will query for the number of dead-letter-messages/poison-messages- Returns:
- the number of queued messages for the given queue
-
getTotalDeadLetterMessagesQueuedFor
Get the total number of dead-letter-messages/poison-messages queued for the given queue- Parameters:
operation- theGetTotalDeadLetterMessagesQueuedForoperation- Returns:
- the number of queued messages for the given queue
-
getQueuedMessages
default List<QueuedMessage> getQueuedMessages(QueueName queueName, DurableQueues.QueueingSortOrder queueingSortOrder, long startIndex, long pageSize) Query Queued Messages (i.e. not including any Dead Letter Messages) for the given Queue- Parameters:
queueName- the name of the Queue where we will query for queued messagesqueueingSortOrder- the sort order for theQueuedMessage.getId()startIndex- the index of the first message to include in the result (used for pagination)pageSize- how many messages to include in the result (used for pagination)- Returns:
- the messages matching the criteria
-
getQueuedMessages
Query Queued Messages (i.e. not including any Dead Letter Messages) for the given Queue- Parameters:
operation- theGetQueuedMessagesoperation- Returns:
- the messages matching the criteria
-
getDeadLetterMessages
default List<QueuedMessage> getDeadLetterMessages(QueueName queueName, DurableQueues.QueueingSortOrder queueingSortOrder, long startIndex, long pageSize) Query Dead Letter Messages (i.e. not normal Queued Messages) for the given Queue- Parameters:
queueName- the name of the Queue where we will query for Dead letter messagesqueueingSortOrder- the sort order for theQueuedMessage.getId()startIndex- the index of the first message to include in the result (used for pagination)pageSize- how many messages to include in the result (used for pagination)- Returns:
- the dead letter messages matching the criteria
-
getDeadLetterMessages
Query Dead Letter Messages (i.e. not normal Queued Messages) for the given Queue- Parameters:
operation- theGetDeadLetterMessagesoperation- Returns:
- the dead letter messages matching the criteria
-
purgeQueue
Delete all messages (Queued or Dead letter Messages) in the given queue- Parameters:
queueName- the name of the Queue where all the messages will be deleted- Returns:
- the number of deleted messages
-
purgeQueue
Delete all messages (Queued or Dead letter Messages) in the given queue- Parameters:
operation- thePurgeQueueoperation- Returns:
- the number of deleted messages
-
queryForMessagesSoonReadyForDelivery
default List<NextQueuedMessage> queryForMessagesSoonReadyForDelivery(QueueName queueName, int maxNumberOfMessagesToReturn) Query for the nextmaxNumberOfMessagesToReturnqueued messages that are soon ready to be delivered usingInstant.now()aswithNextDeliveryTimestampAfter
This is a useful method for a custom queue consumer to know if it's necessary to callgetNextMessageReadyForDelivery(GetNextMessageReadyForDelivery)- Parameters:
queueName- the name of the queue being queriedmaxNumberOfMessagesToReturn- the maximum number of messages to return- Returns:
- the messages soon ready to be delivered
-
queryForMessagesSoonReadyForDelivery
List<NextQueuedMessage> queryForMessagesSoonReadyForDelivery(QueueName queueName, Instant withNextDeliveryTimestampAfter, int maxNumberOfMessagesToReturn) Query for the nextmaxNumberOfMessagesToReturnqueued messages that are soon ready to be delivered
This is a useful method for a custom queue consumer to know if it's necessary to callgetNextMessageReadyForDelivery(GetNextMessageReadyForDelivery)- Parameters:
queueName- the name of the queue being queriedwithNextDeliveryTimestampAfter- returnNextQueuedMessagewith aNextQueuedMessage.nextDeliveryTimestamp> than this timestampmaxNumberOfMessagesToReturn- the maximum number of messages to return- Returns:
- the messages soon ready to be delivered
-