1

I've the following flow:

@Resource(name = S3_CLIENT_BEAN)
private MessageSource<InputStream> messageSource;

public IntegrationFlow fileStreamingFlow() {
    return IntegrationFlows.from(s3Properties.getFileStreamingInputChannel())
        .enrichHeaders(spec -> spec.header(ERROR_CHANNEL, S3_ERROR_CHANNEL, true))
        .handle(String.class, (fileName, h) -> {
                    if (messageSource instanceof S3StreamingMessageSource) {
                        S3StreamingMessageSource s3StreamingMessageSource = (S3StreamingMessageSource) messageSource;

                        ChainFileListFilter<S3ObjectSummary> chainFileListFilter = new ChainFileListFilter<>();
                        chainFileListFilter.addFilters(...);
                        s3StreamingMessageSource.setFilter(chainFileListFilter);

                        return s3StreamingMessageSource.receive();
                    }                    
                    return messageSource.receive();
                }, spec -> spec
                        .requiresReply(false) // in case all messages got filtered out
        )
        .channel(s3Properties.getFileStreamingOutputChannel())
        .get();
}

I found that if s3StreamingMessageSource.receive throws an exception, the error ends up in the error channel configured for the previous flow in the pipeline, not the S3_ERROR_CHANNEL that's configured for this flow. Not sure if it's related to this question.

Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219

1 Answers1

1

The s3StreamingMessageSource.receive() is called from the SourcePollingChannelAdapter:

protected Message<?> receiveMessage() {
    return this.source.receive();
}

This one called from the AbstractPollingEndpoint:

private boolean doPoll() {

        message = this.receiveMessage();
...

        this.handleMessage(message);
...
}

That handleMessage() does this:

this.messagingTemplate.send(getOutputChannel(), message);

So, that is definitely still far away from the mentioned .enrichHeaders(spec -> spec.header(ERROR_CHANNEL, S3_ERROR_CHANNEL, true)) downstream.

However you still can catch an exception in that S3_ERROR_CHANNEL. Pay attention to the second argument of the IntegrationFlows.from():

IntegrationFlows.from(s3Properties.getFileStreamingInputChannel(),
           e -> e.poller(Pollers.fixedDelay(...)
                       .errorChannel(S3_ERROR_CHANNEL)))

Or, according your current you have somewhere a global poller, so configure an errorChannel there.

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • I don’t have a poller. Can I do something using advice or `MessagePublishingErrorHandler`? – Abhijit Sarkar Apr 19 '18 at 02:30
  • Well, there definitely has to be a poller somewhere in your application context. Otherwise `MessageSource` doesn’t work. And if you can’t modify that one, just configure a local one using API I suggested. Yes, you can consider to implement some advice with the mentioned publisher, but why reinvent the wheel if the `errorChannel` on the poller does the logic for you already – Artem Bilan Apr 19 '18 at 02:36
  • There is probably a poller somewhere (not near code), but not related to the flow shown. The flow shown is triggered by putting a message in the input channel. See [this](https://stackoverflow.com/q/48016794/839733) – Abhijit Sarkar Apr 19 '18 at 05:53
  • OK! You had to mention in the question that you call `MessageSource.receive()` manually. So, that is really natural that exception from that `receive()` are still far away from the mentioned header enricher. So, yes, you have to `try...catch` that manual call and ensure error message sending manually. – Artem Bilan Apr 19 '18 at 14:46
  • Do you have any recommendations/examples for how to send error message manually? – Abhijit Sarkar Apr 20 '18 at 17:16
  • The `MessagePublishingErrorHandler` is the best choice. It can be supplied with the `ErrorMessageStrategy` – Artem Bilan Apr 20 '18 at 17:21
  • I'll try your suggestion on the other ticket and accept this answer afterwards. – Abhijit Sarkar Apr 20 '18 at 19:12