We are really confused with error handling in Spring Integration. We are using Boot 2.0.2 and Kotlin.
Within a @Transformer
we throw an Exception X
.
Also, within a Java DSL flow definition, we throw the same exception X
Channels
@Bean(TO_BE_PROCESSED_CHANNEL)
fun toBeProcessed() = PublishSubscribeChannel(defaultExecutor())
Flow
@Configuration
class VideoDescriptorPersistSubflow(
val videoRepository: JdbcVideoRepository,
val ingestRecordRepository: CustomIngestRecordRepository
) {
@Bean
fun videoDescriptorPersistFlow(
toBeProcessed: MessageChannel,
processedVideos: MessageChannel
) =
IntegrationFlows.from(toBeProcessed)
.filter { message: Message<*> -> message.ingestRecordId() != null }
.handle { videoDescriptor: VideoDescriptor, _ -> validateVideoDescriptor(videoDescriptor) }
.handle { videoDescriptor: VideoDescriptor, _ -> videoRepository.persist(videoDescriptor) }
.channel(processedVideos)
.get()
fun validateVideoDescriptor(videoDescriptor: VideoDescriptor): VideoDescriptor {
val errors = VideoDescriptorValidator().validate(videoDescriptor)
if (errors.isNotEmpty()) {
throw VideoMetadataValidationException(errors)
}
return videoDescriptor
}
Later in the errorChannel
we filter out X
and do some stuff. At that point we need the failed message.
For the exception thrown by the @Transformer
the originalMessage is there.
For the one thrown from the java DSL subflow, the originalMessage is null.
We did some digging and realised, the former is wrapped in MessagingExceptionWrapper
whereas the later is wrapped in a MessageHandlingException
which does not contain a reference to the original message.
Could someone please help us understand under what circumstances Spring Integration wraps using what exceptions? Docs do not say much here, or we couldn't find anything relevant.
UPDATE: CHANGING FROM PUBSUB TO QUEUE CHANNEL MAKES IT WORK...
UPDATE 2: Following Gary's advide we are now using payload.failed message, which works just fine. There is something dodgy though with originalMessage in ErrorMessage.
payload.failedMessage
is the message at the time of failure. ErrorMessage.originalMessage
is the message at the start of the flow. It is not populated in all cases.