Spring batch 使用Spring批处理集成为AWS S3中的每个新文件启动JobLaunchRequest

Spring batch 使用Spring批处理集成为AWS S3中的每个新文件启动JobLaunchRequest,spring-batch,spring-integration,spring-integration-aws,Spring Batch,Spring Integration,Spring Integration Aws,我遵循以下文档:结合用于汇集AWS S3的 但在某些情况下,每个文件的批处理执行不起作用 AWS S3池工作正常,因此当我放入新文件或启动应用程序时,应用程序会与本地目录同步: @Bean public S3SessionFactory s3SessionFactory(AmazonS3 pAmazonS3) { return new S3SessionFactory(pAmazonS3); } @Bean public S3Inboun

我遵循以下文档:结合用于汇集AWS S3的

但在某些情况下,每个文件的批处理执行不起作用

AWS S3池工作正常,因此当我放入新文件或启动应用程序时,应用程序会与本地目录同步:

    @Bean
    public S3SessionFactory s3SessionFactory(AmazonS3 pAmazonS3) {
        return new S3SessionFactory(pAmazonS3);
    }

    @Bean
    public S3InboundFileSynchronizer s3InboundFileSynchronizer(S3SessionFactory pS3SessionFactory) {
        S3InboundFileSynchronizer synchronizer = new S3InboundFileSynchronizer(pS3SessionFactory);
        synchronizer.setPreserveTimestamp(true);
        synchronizer.setDeleteRemoteFiles(false);
        synchronizer.setRemoteDirectory("remote-bucket");
        //synchronizer.setFilter(new S3PersistentAcceptOnceFileListFilter(new SimpleMetadataStore(), "simpleMetadataStore"));
        return synchronizer;
    }

    @Bean
    @InboundChannelAdapter(value = IN_CHANNEL_NAME, poller = @Poller(fixedDelay = "30"))
    public S3InboundFileSynchronizingMessageSource s3InboundFileSynchronizingMessageSource(
            S3InboundFileSynchronizer pS3InboundFileSynchronizer) {
        S3InboundFileSynchronizingMessageSource messageSource = new S3InboundFileSynchronizingMessageSource(pS3InboundFileSynchronizer);
        messageSource.setAutoCreateLocalDirectory(true);
        messageSource.setLocalDirectory(new FileSystemResource("files").getFile());
        //messageSource.setLocalFilter(new FileSystemPersistentAcceptOnceFileListFilter(new SimpleMetadataStore(), "fsSimpleMetadataStore"));
        return messageSource;
    }

    @Bean("s3filesChannel")
    public PollableChannel s3FilesChannel() {
        return new QueueChannel();
    }
我遵循了教程,因此创建了
文件messagetojobrequest
我不会将代码放在这里,因为它与文档相同

因此,我创建了beans IntegrationFlow和FileMessageToJobRequest:

    @Bean
    public IntegrationFlow integrationFlow(
            S3InboundFileSynchronizingMessageSource pS3InboundFileSynchronizingMessageSource) {
        return IntegrationFlows.from(pS3InboundFileSynchronizingMessageSource, 
                         c -> c.poller(Pollers.fixedRate(1000).maxMessagesPerPoll(1)))
                .transform(fileMessageToJobRequest())
                .handle(jobLaunchingGateway())
                .log(LoggingHandler.Level.WARN, "headers.id + ': ' + payload")
                .get();
    }

    @Bean
    public FileMessageToJobRequest fileMessageToJobRequest() {
        FileMessageToJobRequest fileMessageToJobRequest = new FileMessageToJobRequest();
        fileMessageToJobRequest.setFileParameterName("input.file.name");
        fileMessageToJobRequest.setJob(delimitedFileJob);
        return fileMessageToJobRequest;
    }
因此,在JobLaunchingGateway中,我认为问题在于:

如果我这样创作:

    @Bean
    public JobLaunchingGateway jobLaunchingGateway() {
        SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
        simpleJobLauncher.setJobRepository(jobRepository);
        simpleJobLauncher.setTaskExecutor(new SyncTaskExecutor());
        JobLaunchingGateway jobLaunchingGateway = new JobLaunchingGateway(simpleJobLauncher);

        return jobLaunchingGateway;
    }
案例1(应用程序启动时,存储桶为空)

  • 我在AWS S3中上传了一个新文件
  • 池工作,文件显示在本地目录中
  • 但变革/工作并没有被解雇
案例2(应用程序启动时,Bucket已经有一个文件了):

  • 该作业已启动:
  • 如果在S3中添加第二个文件,则不会像案例1那样启动作业
案例3(存储桶有多个文件):

  • 文件已在本地目录中正确同步
  • 但对于最后一个文件,作业只执行一次

因此,按照以下步骤,我将网关更改为:

    @Bean
    @ServiceActivator(inputChannel = IN_CHANNEL_NAME, poller = @Poller(fixedRate="1000"))
    public JobLaunchingGateway jobLaunchingGateway() {
        SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
        simpleJobLauncher.setJobRepository(jobRepository);
        simpleJobLauncher.setTaskExecutor(new SyncTaskExecutor());

        //JobLaunchingGateway jobLaunchingGateway = new JobLaunchingGateway(jobLauncher());
        JobLaunchingGateway jobLaunchingGateway = new JobLaunchingGateway(simpleJobLauncher);
        //jobLaunchingGateway.setOutputChannel(replyChannel());
        jobLaunchingGateway.setOutputChannel(s3FilesChannel());
        return jobLaunchingGateway;
    }
在这个新的网关实现中,如果我在S3中放入一个新文件,应用程序会做出反应,但不会转换,从而产生错误:

Caused by: java.lang.IllegalArgumentException: The payload must be of type JobLaunchRequest. Object of class [java.io.File] must be an instance of class org.springframework.batch.integration.launch.JobLaunchRequest
如果bucket中有两个文件(当应用程序启动时)FILE1.csv和FILE2.csv,则会正确运行FILE1.csv的作业,但给出上面FILE2.csv的错误

实现这样的事情的正确方法是什么

为了清楚起见,我想在这个桶中接收数千个csv文件,用Spring批处理读取和处理,但我还需要尽快从S3获取每个新文件


提前感谢。

确实,
JobLaunchingGateway
只希望我们将
JobLaunchRequest
作为有效负载

既然您在
S3InboundFileSynchronizingMessageSource
bean定义上有
@InboundChannelAdapter(value=IN\u CHANNEL\u NAME,poller=@poller(fixedDelay=“30”)
,那么使用
@ServiceActivator确实是错误的(inputChannel=IN_CHANNEL_NAME
用于该
JobLaunchingGateway
之间没有
FileMessageToJobRequest
转换器

您的
integrationFlow
对我来说看起来不错,但是您确实需要从
S3InboundFileSynchronizingMessageSource
bean中删除该
@InboundChannelAdapter
,并完全依赖
c.poller()
配置

另一种方法是离开
@InboundChannelAdapter
,然后从
IN\u CHANNEL\u NAME
而不是
消息源启动
集成流


由于您对同一个S3源有多个轮询器,加上这两个轮询器都基于同一个本地目录,因此看到如此多的意外情况并不奇怪。

您是对的。愚蠢的错误…我决定从S3InboundFile中删除@InboundChannelAdapter,它可以正常工作。好吧,这并不愚蠢,尤其是当您复制/粘贴它时从某个地方开始。甚至有可能做到这一点,并且在您的应用程序中有如此复杂的配置。您有点支持S3的并发消费者。但我很高兴它这么容易修复!是的,我没有阅读这两个文档并结合样本。您认为我所做的是适合我的情况的正确方法吗?我是说在可伸缩性方面例如,100k文件上载到my bucket和my app scales,使用此方法进行批量集成时,它们是否会同时尝试处理同一文件?如果要进行扩展,则需要考虑使用共享元数据存储的持久文件列表过滤器。请参阅Spring integration中的FTP文档。
Caused by: java.lang.IllegalArgumentException: The payload must be of type JobLaunchRequest. Object of class [java.io.File] must be an instance of class org.springframework.batch.integration.launch.JobLaunchRequest