Kotlin 驼峰:当项目数量小于批次大小时,如何拆分然后聚合

Kotlin 驼峰:当项目数量小于批次大小时,如何拆分然后聚合,kotlin,apache-camel,spring-camel,Kotlin,Apache Camel,Spring Camel,我有一个骆驼路由,它从S3读取文件,并按如下方式处理输入文件: 使用 按body()拆分输出 按主体属性(.sement)和批大小2进行聚合 调用持久性服务以在给定的批中上载到DB 问题是,当批大小为2且记录数为奇数时,总有一条记录无法保存 提供的代码与等价的Java代码(除了“\${simple expression}”前面的斜杠或没有分号来终止语句)没有太大区别 如果我将批大小设置为1,则会保存每条记录,否则最后一条记录将永远不会保存 我已经检查了几次文档,但它似乎没有涵盖这个特定场景 除了

我有一个骆驼路由,它从S3读取文件,并按如下方式处理输入文件:

  • 使用
  • 按body()拆分输出
  • 按主体属性(
    .sement
    )和批大小2进行聚合
  • 调用持久性服务以在给定的批中上载到DB
  • 问题是,当批大小为2且记录数为奇数时,总有一条记录无法保存

    提供的代码与等价的Java代码(除了“\${simple expression}”前面的斜杠或没有分号来终止语句)没有太大区别

    如果我将批大小设置为1,则会保存每条记录,否则最后一条记录将永远不会保存

    我已经检查了几次文档,但它似乎没有涵盖这个特定场景

    除了
    completionSize
    之外,我还设置了[
    completionTimeout
    |
    completionInterval
    ],但没有任何区别

    以前有人遇到过这个问题吗

    val csvDataFormat = BindyCsvDataFormat(Student::class.java)
    
    from("aws-s3://$student-12-bucket?amazonS3Client=#amazonS3&delay=5000")
        .log("A new Student input file has been received in S3: '\${header.CamelAwsS3BucketName}/\${header.CamelAwsS3Key}'")
        .to("direct:move-input-s3-object-to-in-progress")
        .to("direct:process-s3-file")
        .to("direct:move-input-s3-object-to-completed")
        .end()
    
    from("direct:process-s3-file")
        .unmarshal(csvDataFormat)
        .split(body())
        .streaming()
        .parallelProcessing()
        .aggregate(simple("\${body.semester}"), GroupedBodyAggregationStrategy())
        .completionSize(2)
        .bean(persistenceService)
        .end()
    
    对于包含七(7)条记录的输入CSV文件,这是生成的输出(添加了一些调试日志):

    WARN 19540---[student-12-move]c.a.s.s.internal.S3AbortableInputStream:没有从S3ObjectInputStream读取所有字节,正在中止HTTP连接。这可能是一个错误,可能会导致次优行为。使用后,仅通过范围GET请求所需的字节,或排空输入流。 信息19540---[student-12-move]学生工作流程主:在S3中收到一个新的学生输入文件:“student-12-bucket/inbox/foo.csv” 信息19540---[student-12-move]move-input-s3-object-to-in-progress:将s3文件“inbox/foo.csv”移动到“Ingress”文件夹。。。 信息19540---[student-12-move]学生工作流程主:将输入S3文件'in progress/foo.csv'移动到'in progress'文件夹。。。 信息19540---[student-12-move]预处理-s3-file-records:开始保存到数据库。。。 DEBUG 19540---[read#7-Split]c.b.i.d.s.StudentPersistenceServiceImpl:将记录保存到数据库:Student(id=7,name=Student 7,学期=2,javaMarks=25) DEBUG 19540---[read#7-Split]c.b.i.d.s.StudentPersistenceServiceImpl:将记录保存到数据库:Student(id=5,name=Student 5,Semmer=2nd,javaMarks=81) DEBUG 19540---[read#3-Split]c.b.i.d.s.StudentPersistenceServiceImpl:将记录保存到数据库:Student(id=6,name=Student 6,学期=1,javaMarks=15) DEBUG 19540---[read#3-Split]c.b.i.d.s.StudentPersistenceServiceImpl:将记录保存到数据库:Student(id=2,name=Student 2,学期=1,javaMarks=62) DEBUG 19540---[read#2-Split]c.b.i.d.s.StudentPersistenceServiceImpl:将记录保存到数据库:Student(id=3,name=Student 3,学期=2,javaMarks=72) DEBUG 19540---[read#2-Split]c.b.i.d.s.StudentPersistenceServiceImpl:将记录保存到数据库:Student(id=1,name=Student 1,学期=2,javaMarks=87) 信息19540---[student-12-move]设备组工作流主:结束预处理S3 CSV文件记录。。。 信息19540---[student-12-move]move-input-s3-object-to-completed:将s3文件'in progress/foo.csv'移动到'completed'文件夹。。。 信息19540---[student-12-move]设备组工作流主:将S3文件“进行中/foo.csv”移动到“完成”文件夹。。。
    如果需要立即完成消息,则可以指定一个基于拆分器设置的exchange属性的完成谓词

    .completionPredicate( simple( "${exchangeProperty.CamelSplitComplete}" ) )
    
    将处理最后一条消息


    我的另一个担忧是,您在拆分器中设置了
    parallelProcessing
    ,这可能意味着消息没有按顺序进行处理。这真的是您希望并行处理应用到的拆分器,还是实际上是聚合器?您似乎没有对拆分记录执行任何操作,只是对它们进行聚合,然后再对它们进行处理o最好将
    并行处理
    指令移动到聚合器。

    completionTimeout应该在超时时触发最后一行。如果这不起作用,那会很奇怪。如果我将simple(${body.sement})替换为常量(true),它确实表现出正确的行为。这可能是一个错误…您使用的是什么版本的Camel?组键body.sement或constant不应影响超时。我使用的是以下组件:+Camel.version=2.23.0+spring-boot.version=2.1.1.RELEASE+kotlin.version=1.3.10+aws-java-sdk.version=1.11.461并且您确定y中没有任何错误我们的bean不能只处理1条记录。您是否尝试过在聚合后添加日志,以查看它在触发完成超时时是否记录了一些内容等。如果仍然存在问题,您可以尝试在github上构建一个项目,以便其他人更容易查看。并且可以在没有AWS帐户的情况下轻松运行等。但事实并非如此但它帮助我理解了问题的原因。问题似乎是,当按主体的某个属性分组时,可能会有一些结转交换,这些交换的完成条件都不会为真:*交换完成大小==2*exchangeProperty.CamelSplitComplete==真不确定如何这样做lve还没有..可能关闭并行处理,因为您可以启用无序处理。我确实按照建议在拆分期间关闭了并行处理。不过最终结果是一样的。。
    .completionPredicate( simple( "${exchangeProperty.CamelSplitComplete}" ) )