Spring Integration
  1. Spring Integration
  2. INT-343

Add a RetryInterceptor for MessageConsumers

    Details

      Description

      A naive implementation of retry logic used to exist within the SimpleDispatcher but has since been removed (and SimpleDispatcher lives up to its name as a result). For more detail on that refactoring, see: INT-337

      Since the applicability of retry behavior should be a per-target concern, it would be best to provide a RetryInterceptor implementation that can be configured for any MessageConsumer (for example, when RemoteAccessExceptions or JMS ResourceAllocationExceptions occur). This could be modeled after the Spring Batch retryTemplate.

        Issue Links

          Activity

          Hide
          Mark Fisher added a comment -

          Moving to RC1. I now believe that we have 3 options for this (opinions/suggestions please!):

          1) add an interceptor for "gateways" (which would also give us a clear place to add Transaction support or anything that can be wrapped around request/reply as opposed to one-way void returning methods like the MessageHandler)

          2) add as a ChannelInterceptor

          3) add as regular AOP advice for either the particular MessageHandler instance or a the ref'ed POJO.

          Show
          Mark Fisher added a comment - Moving to RC1. I now believe that we have 3 options for this (opinions/suggestions please!): 1) add an interceptor for "gateways" (which would also give us a clear place to add Transaction support or anything that can be wrapped around request/reply as opposed to one-way void returning methods like the MessageHandler) 2) add as a ChannelInterceptor 3) add as regular AOP advice for either the particular MessageHandler instance or a the ref'ed POJO.
          Hide
          Dave Syer added a comment -

          A clearer statement of the use cases would help, instead of concentrating on the implementation. Useful background reading can also be found here: http://static.springsource.org/spring-batch/cases/retry.html. Note that there are 2 independent general classes of retry (stateless and stateful), both described in that link, but note that one (stateful or external) is expressed as a variation of the other, which isn't particularly illuminating. Both are relevant to Spring Integration users.

          Stateless retry (where an exception does not invalidate the current transaction, or there is no current transaction) can be simply implemented as advice around a MessageHandler. The POJO in a user-defined endpoint (and any vanilla <gateway/>) can already be wrapped in advice trivially using Spring AOP, so maybe all we need to provide is the interceptor and maybe some configuration sugar to make it easy to use. Note, however, that the important case of an outbound gateway like a web-service call is not covered by that implementation, so we may need to consider that as a special case.

          Stateful retry is needed in the opposite case (an exception invalidates the current transaction), but can be supported only if there is a transaction and only if a rollback would result in redelivery. Retry features can be added to any handler or equivalently any channel in a transactional message pipeline formed (of course) from DirectChannels where there is an upstream JMS inbound adapter or a transactional poller. As far as implementation goes, the Spring JMS listener containers have rudimentary support for retry built in to them (too rudimentary for some clients but that's another story), so I believe we should concentrate on the poller (where advice is already supported, largely because we anticipated this use case in 1.0).

          Assuming we don't want to depend on Spring Batch, and we also don't want to duplicate all the code there in the long term, we should probably adopt the approach Thomas is taking with database support and depend on a common library that can be shared between Batch, Integration and the database package(s).

          Show
          Dave Syer added a comment - A clearer statement of the use cases would help, instead of concentrating on the implementation. Useful background reading can also be found here: http://static.springsource.org/spring-batch/cases/retry.html . Note that there are 2 independent general classes of retry (stateless and stateful), both described in that link, but note that one (stateful or external) is expressed as a variation of the other, which isn't particularly illuminating. Both are relevant to Spring Integration users. Stateless retry (where an exception does not invalidate the current transaction, or there is no current transaction) can be simply implemented as advice around a MessageHandler. The POJO in a user-defined endpoint (and any vanilla <gateway/>) can already be wrapped in advice trivially using Spring AOP, so maybe all we need to provide is the interceptor and maybe some configuration sugar to make it easy to use. Note, however, that the important case of an outbound gateway like a web-service call is not covered by that implementation, so we may need to consider that as a special case. Stateful retry is needed in the opposite case (an exception invalidates the current transaction), but can be supported only if there is a transaction and only if a rollback would result in redelivery. Retry features can be added to any handler or equivalently any channel in a transactional message pipeline formed (of course) from DirectChannels where there is an upstream JMS inbound adapter or a transactional poller. As far as implementation goes, the Spring JMS listener containers have rudimentary support for retry built in to them (too rudimentary for some clients but that's another story), so I believe we should concentrate on the poller (where advice is already supported, largely because we anticipated this use case in 1.0). Assuming we don't want to depend on Spring Batch, and we also don't want to duplicate all the code there in the long term, we should probably adopt the approach Thomas is taking with database support and depend on a common library that can be shared between Batch, Integration and the database package(s).
          Hide
          Mark Fisher added a comment -

          Dave, I'm assigning this to you, because you are clearly the expert. I was planning to just move the target to 2.1 where we can depend on 3.1 and possibly add a general purpose handlerInterceptor support as well (we will most likely want to add support for a CachingInterceptor in the 2.1 timeframe as well). I will leave it up to you though if you do think 2.1 is the proper target.

          Show
          Mark Fisher added a comment - Dave, I'm assigning this to you, because you are clearly the expert. I was planning to just move the target to 2.1 where we can depend on 3.1 and possibly add a general purpose handlerInterceptor support as well (we will most likely want to add support for a CachingInterceptor in the 2.1 timeframe as well). I will leave it up to you though if you do think 2.1 is the proper target.
          Hide
          Mark Fisher added a comment -

          Moving to 2.2 which is now the first version of Spring Integration that will depend upon Spring 3.1

          Show
          Mark Fisher added a comment - Moving to 2.2 which is now the first version of Spring Integration that will depend upon Spring 3.1
          Hide
          Gary Russell added a comment -

          I will put together a straw-man using the stateful/stateless recovery features of spring-retry 1.0.1.

          Show
          Gary Russell added a comment - I will put together a straw-man using the stateful/stateless recovery features of spring-retry 1.0.1.

            People

            • Assignee:
              Gary Russell
              Reporter:
              Mark Fisher
            • Votes:
              13 Vote for this issue
              Watchers:
              24 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - 1.5d
                1.5d
                Remaining:
                Remaining Estimate - 1.5d
                1.5d
                Logged:
                Time Spent - Not Specified
                Not Specified