Spring batch 使用Spring批处理集成为AWS S3中的每个新文件启动JobLaunchRequest
我遵循以下文档:结合用于汇集AWS S3的 但在某些情况下,每个文件的批处理执行不起作用 AWS S3池工作正常,因此当我放入新文件或启动应用程序时,应用程序会与本地目录同步: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
@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中上传了一个新文件李>
- 池工作,文件显示在本地目录中李>
- 但变革/工作并没有被解雇李>
- 该作业已启动:
- 如果在S3中添加第二个文件,则不会像案例1那样启动作业
- 文件已在本地目录中正确同步
- 但对于最后一个文件,作业只执行一次
因此,按照以下步骤,我将网关更改为:
@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