INT-4527: Delayer Retries and Error Handling

JIRA: https://jira.spring.io/browse/INT-4527
Fixes https://github.com/spring-projects/spring-integration/issues/2543

- Add error handling within the scope of a transaction
- Add `retryDelay` and `maxAttempts`
- Include the delivery attempt header in the `ErrorMessage`
- Add `transactionalRelease()` methods to the DSL

Check context in `ContextRefreshedEvent`.

Complete test case; don't schedule for re-release after a successful send after a failure.

Use `identityHashCode` for deliveries map key - error flow might change the message `hashCode`.

Debug logging

Polishing; remove parameter from the `DelayerEndpointSpec.transactionalRelease()`

* Polishing some code style
This commit is contained in:
Gary Russell
2018-08-23 13:51:42 -04:00
committed by Artem Bilan
parent 68bccdc155
commit 075d237c04
5 changed files with 469 additions and 154 deletions

View File

@@ -134,6 +134,8 @@ TIP: `ThreadPoolTaskScheduler` has a property `errorHandler`, which can be injec
This handler allows processing an `Exception` from the thread of the scheduled task sending the delayed message.
By default, it uses an `org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler`, and you can see a stack trace in the logs.
You might want to consider using an `org.springframework.integration.channel.MessagePublishingErrorHandler`, which sends an `ErrorMessage` into an `error-channel`, either from the failed message's header or into the default `error-channel`.
This error handling is performed after a transaction rolls back (if present).
See <<delayer-release-failures>>.
[[delayer-message-store]]
==== Delayer and a Message Store
@@ -172,8 +174,6 @@ The following example shows an `advice-chain` within a `<delayer>`:
----
====
// TODO: It would be good to have an example of the <transactional> element here.
The `DelayHandler` can be exported as a JMX `MBean` with managed operations (`getDelayedMessageCount` and `reschedulePersistedMessages`), which allows the rescheduling of delayed persisted messages at runtime -- for example, if the `TaskScheduler` has previously been stopped.
These operations can be invoked through a `Control Bus` command, as the following example shows:
@@ -187,3 +187,20 @@ Message<String> delayerReschedulingMessage =
====
NOTE: For more information regarding the message store, JMX, and the control bus, see <<system-management-chapter>>.
[[delayer-release-failures]]
==== Release Failures
Starting with version 5.0.8, there are two new properties on the delayer:
- `maxAttempts` (default 5)
- `retryDelay` (default 1 second)
When a message is released, if the downstream flow fails, the release will be attempted after the `retryDelay`.
If the `maxAttempts` is reached, the message is discarded (unless the release is transactional, in which case the message will remain in the store, but will no longer be scheduled for release, until the application is restarted, or the `reschedulePersistedMessages()` method is invoked, as discussed above).
In addition, you can configure a `delayedMessageErrorChannel`; when a release fails, an `ErrorMessage` is sent to that channel with the exception as the payload and has the `originalMessage` property.
The `ErrorMessage` contains a header `IntegrationMessageHeaderAccessor.DELIVERY_ATTEMPT` containing the current count.
If the error flow consumes the error message and exits normally, no further action is taken; if the release is transactional, the transaction will commit and the message deleted from the store.
If the error flow throws an exception, the release will be retried up to `maxAttempts` as discussed above.