0

I am creating a simple integration service with AWS S3. I am facing some difficulties when an exception occurs.

My requirement is to poll an S3 Bucket periodically and to apply some transformation whenever a file is newly placed into S3 Bucket. The below code snippet works fine, but when an exception occurs it continues to retry again and again. I do not want that to happen. Can someone help me here.,

The IntegrationFlow is defined as below.,

    @Configuration
    public class S3Routes {
    
        @Bean
        public IntegrationFlow downloadFlow(MessageSource<InputStream> s3InboundStreamingMessageSource) {
    
            return IntegrationFlows.from(s3InboundStreamingMessageSource)
                                   .channel("s3Channel")
                                   .handle("QueryServiceImpl", "processFile")
                

                   .get();
    }

}

Configuration file is as below.,

@Service
public class S3AppConfiguration {

    @Bean
    @InboundChannelAdapter(value = "s3Channel")
    public MessageSource<InputStream> s3InboundStreamingMessageSource(S3RemoteFileTemplate template) {

        S3StreamingMessageSource messageSource = new S3StreamingMessageSource(template);
        messageSource.setRemoteDirectory("my-bucket-name");
        messageSource.setFilter(new S3PersistentAcceptOnceFileListFilter(new SimpleMetadataStore(),
                                                                         "streaming"));

        return messageSource;
    }

    @Bean
    public PollableChannel s3Channel() {
        return new QueueChannel();
    }

    @Bean
    public S3RemoteFileTemplate template(AmazonS3 amazonS3) {
        return new S3RemoteFileTemplate(new S3SessionFactory(amazonS3));
    }

    @Bean(name = "amazonS3")
    public AmazonS3 nonProdAmazonS3(BasicAWSCredentials basicAWSCredentials) {
        ClientConfiguration config = new ClientConfiguration();
        config.setProxyHost("localhost");
        config.setProxyPort(3128);

        return AmazonS3ClientBuilder.standard().withRegion(Regions.fromName("ap-southeast-1"))
                                    .withCredentials(new AWSStaticCredentialsProvider(basicAWSCredentials))
                                    .withClientConfiguration(config)
                                    .build();
    }

    @Bean
    public BasicAWSCredentials basicAWSCredentials() {
        return new BasicAWSCredentials("access_key", "secret_key");
    }

    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerMetadata nonProdPoller() {

        return Pollers.cron("* */2 * * * *")
                      .get();
    }
}

AcceptOnceFileList filter that I have used here, helps me to prevent handling the same file for continuous retries. But, I do not want to use AcceptOnceFileList filter, because when a file is not processed on 1st attempt, I wish to retry on next Poll (usually it happens every 1 hour in Prod region). I tried to use filter.remove() method whenever the processing fails(in case of any exception), it again results in continuous retries.

I am not sure how to disable the continuous retries on failure. Where should I configure it?

I took a look at Spring Integration ( Retry Strategy). Same scenario, but a different integration. I am not sure how to set up this for my IntegrationFlow. Can someone help here? Thanks in advance

Muruga Balu
  • 115
  • 10

1 Answers1

0
  1. That story is different: it talks about a listener container for AMQP. You use a source polling channel adapter - the approach might be different.

  2. You create two source polling channel adapters: one via that @InboundChannelAdapter, another via IntegrationFlows.from(s3InboundStreamingMessageSource). Both of them produces data to the same channel. Not sure if that is really intentional.

  3. It is not clear what is that retry in your case unless you really do that manual filter.remove() call. In this case indeed it is going to retry. But this is a single, not controlled retry. It is going to retry again only if you call that filter.remove() again. So, if you do everything yourself, why is the question?

  4. Consider to use a RequestHandlerRetryAdvice configured for that your handle() instead: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#message-handler-advice-chain. This way you really going to pull the remote file only once and retry is going to be managed by the Spring Retry API.

UPDATE

So, after some Cron Expression learning I realized that your one is wrong:

* */2 * * * * - means every second of every even minute

Must be like this:

0 */2 * * * * - at the beginning of every even minute

Perhaps something similar is with your hourly cron expression on the prod...

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Yes I am manually performing the filter.remove() method. Because, I want the Poller to pick the file in next hour. Say the application runs at 10:00 AM - It fails, keeps retrying 20-30 times non stop. Waits for the next poll (an hour latter) 11:00 AM - It fails, keeps retrying 20-30 times non stop. When I do not use the filter.remove() method., The application runs at 10:00 AM - It fails once and does nothing. No retries too And does not pick it up after 1 hour i.e., during the next Poll (11:00 AM). I want to pick the file on every Poll and not to attempt multiple retries – Muruga Balu Jul 06 '22 at 16:08
  • What you are saying has to work out-of-the-box with that `filter.remove()`. I'm not sure from where that ` 20-30 times non stop` comes. Is there a way to share with us a simple project to reproduce and play with? – Artem Bilan Jul 06 '22 at 16:34
  • I have added a sample code here - https://github.com/Murugabalu/spring-integration. When I run this application I get a connection refused error. But, it does multiple retries in a single run. How should I disable those retries? – Muruga Balu Jul 07 '22 at 14:19
  • So, you didn't listen to me and you still have that `@InboundChannelAdapter(value = "s3Channel")` making two same source polling channel adapters together with that `IntegrationFlow`. How can I test it if it does not connect anywhere? You said you have a problem with rolled back file, but connection problem is fully different... See if you can come up with some testing solution based on the Localstack, e.g. via Testcontainers. I mean I don't have an AWS account to check your solution against real S3 service. – Artem Bilan Jul 07 '22 at 14:38
  • See an UPDATE in my answer. – Artem Bilan Jul 07 '22 at 20:54