来自ftp使用者的异常后聚合:FatalFallbackErrorHandler

时间:2019-03-15 16:38:26

标签: apache-camel sftp

我的骆驼路线尝试从sftp提取一些文件,将它们传输到网络,然后从sftp删除它们。如果3次尝试后sftp无法访问,我希望路由发送一封电子邮件,警告管理员有关此问题的信息。

因此,我的sftp地址具有以下参数:

maximumReconnectAttempts=2&throwExceptionOnConnectFailed=true&consumer.bridgeErrorHandler=true

如果网络位置不可用,我希望路由通知管理员,并从sftp删除文件。 因此,我在onException中设置了 .handled(false)

但是,当连接到sftp失败时,聚合也将失败,并且不会收到电子邮件。我在下面做了一个极简主义的例子:

/configure
  onException(Throwable.class)
    .retryAttemptedLogLevel(LoggingLevel.WARN)
    .redeliveryDelay(1000)
    .handled(false)
    .log(LoggingLevel.ERROR, LOG, "XXX - Error moving files")
    .to(AGGREGATEROUTE)
    .end();

  from(downloadFrom)
  .to(to)
  .log(LoggingLevel.INFO, LOG, "XXX - Moving file OK")
  .to(AGGREGATEROUTE);

  from(AGGREGATEROUTE)
  .log(LoggingLevel.INFO, LOG, "XXX - Starting aggregation.")
  .aggregate(constant(true), new GroupedExchangeAggregationStrategy())
      .completionFromBatchConsumer()
      .completionTimeout(10000)
  .log(LoggingLevel.INFO, LOG, "XXX - Aggregation completed, sending mail.");

在日志中,我看到:

16:02| ERROR | CamelLogger.java 156 | XXX - Error moving files

然后在连接期间发生异常的日志。

然后这个:

16:02| ERROR | FatalFallbackErrorHandler.java 174 | Exception occurred while trying to handle previously thrown exception on exchangeId: ID-LP0641-1552662095664-0-2 using: [Pipeline[[Channel[Log(proefjes.camel_cursus.routebuilders.MoveWithPickupExceptions)[XXX - Error moving files]], Channel[sendTo(direct://aggregate)]]]].
16:02| ERROR | FatalFallbackErrorHandler.java 172 | \--> New exception on exchangeId: ID-LP0641-1552662095664-0-2
   org.apache.camel.component.file.GenericFileOperationFailedException: Cannot connect to sftp://user@mycompany.nl:22
    at org.apache.camel.component.file.remote.SftpOperations.connect(SftpOperations.java:149)

我没有看到“ XXX-开始聚合”。我希望在日志中看到它。聚合之前会发生某种错误吗?永远不会到达聚合(*,*)上的断点。

2 个答案:

答案 0 :(得分:0)

首先,我只想澄清一些事情。您输入“如果网络位置不可用,我希望该路由通知管理员,而不是从sftp删除文件”,但是这样是否不应该如此?我的意思是,如果网络位置不可用,是否可以从sftp删除文件?

您的异常处理程序也在路由.to(AGGREGATEROUTE),这有点令人困惑。假设您要向管理员发送电子邮件,那不应该放在异常处理程序中,而不应该放在幸福的道路上吗?为什么会以及如何“聚合”连接失败?

最后,在这里,我认为您的实现确实存在问题,您可能误解了handled(false)的工作。将此设置为false意味着路由应该停止并将异常传播给调用方。我不确定在这种情况下必须.to(AGGREGATEROUTE)会做什么,但是我不感到惊讶没有被调用。

我建议尝试一些方法。我没有您的代码,所以我不确定哪个会最好。这些都是相关的,任何可能都起作用:

  • handled(false)更改为handled(true)
  • handled替换为continued(true)
  • 使用死信渠道。

参考:

答案 1 :(得分:0)

由于错误处理取决于导致错误的端点,因此我通过使用两个不同版本的onException解决了这一问题:

     //configure exception on sft end
    onException(Throwable.class)
    .maximumRedeliveries(2)
    .retryAttemptedLogLevel(LoggingLevel.WARN)
    .redeliveryDelay(1000)
    .onWhen(new hasSFTPErrorPredicate())
     // .continued(true) //  tries to connect once, mails and continues to aggregation with empty exchange
    //.handled(false) // tries to connect twice but does not reach mail
      .handled(true)  // tries to connect once, does reach mail
    // handled not defined: tries to connect twice but does not reach mail
      .log(LoggingLevel.INFO, LOG, "XXX - SFTP exception")
      .to(MAIL_ROUTE)
      .end();

   // exception anywhere else
    onException(Throwable.class)
     .maximumRedeliveries(2)
     .retryAttemptedLogLevel(LoggingLevel.WARN)
     .redeliveryDelay(1000)
     .log(LoggingLevel.ERROR, LOG, "XXX - Error moving file ${file:name}: ${exception}")
     .to(AGGREGATEROUTE)
     .handled(false)
     .end();

在sftp端发生的异常在第一个onException中处理,因为hasSFTPErrorPredicate返回“ true”。所有这些谓词所做的只是检查消息中是否有任何异常或其原因是否包含“无法连接到sftp:”。 在这种情况下,无需回滚,因为尚未发生任何事情。

其他任何异常都由第二个onException处理。