Azure函数应用内部的Sftp重试逻辑

idfiyjo8  于 2023-01-21  发布在  其他
关注(0)|答案(2)|浏览(122)

我遇到了一个问题,我收到间歇性错误消息
“远程主机强制关闭了现有连接”
尝试连接sftp服务器时。我正在尝试连接azure函数应用程序内部的sftp。我相信此错误发生时存在连接问题。
为了处理这个问题,我需要实现一个重试逻辑,以防这样的错误重复发生,以指定的延迟连接sftp服务器,直到达到配置的最大重试计数。我相信函数应用程序允许的最大执行时间是5分钟(* 需要从azureMaven那里听到它 *)。
有人能帮助我如何在C#中实现这个重试功能吗?
我正在使用Renci.SshNet nuget包来管理sftp

using (var _sftpCn = new SftpClient(host, port, userName, password))
{
    _sftpCn.Connect();//error happens on this line:"An existing connection was forcibly closed by the remote host"
    log.LogInformation("Successful");
    byte[] byteArray = Encoding.UTF8.GetBytes(datacontent);
    sftpCl.WriteAllBytes("{remotePath}", byteArray);
    log.LogInformation("Sent successfully");
    _sftpCn.Disconnect();
}
xtupzzrd

xtupzzrd1#

我建议在这里使用Polly
Polly是一个. NET弹性和瞬时故障处理库,它允许开发人员以流畅和线程安全的方式表达诸如重试、断路器、超时、隔板隔离和回退等策略。
它是免费的库,可以通过以下命令下载为nuget package
dotnet add package Polly
它还有很多功能,请参见herehere以了解更多细节和示例。

9rbhqvlz

9rbhqvlz2#

如果你看一下Connect方法的源代码,你会发现它有关于异常的文档注解,不幸的是,它们都没有提到你所面临的错误消息。
正如您在注解中所说的,您不知道抛出了哪个异常,因为您的日志记录系统只捕获异常的消息,您的怀疑对象是SSHExceptionSShConnectionException
在Polly的情况下,您可以针对这种情况以多种方式定义重试策略
1.使用单个Handle生成器方法

var retryPolicy = Policy
      .Handle<Exception>(ex => ex is SSHException || ex is SShConnectionException)
      .WaitAndRetry(...);

1.使用HandleOr生成器方法

var retryPolicy = Policy
      .Handle<SSHException>()
      .Or<SShConnectionException>()
      .WaitAndRetry(...);

1.如果引发的异常不是任何可疑异常
那么您可以用一种类型安全性较低的方式定义策略

const string ErrorPrefix = "An existing connection was forcibly closed by the remote host";
var retryPolicy = Policy
      .Handle<Exception>(ex => ex.Message.StartsWith(ErrorPrefix) 
          || (ex.InnerException?.Message.StartsWith(ErrorPrefix) ?? false))
      .WaitAndRetry(...);

你也提到
函数app允许的最大执行时间为5分钟
Polly的重试允许您定义最多要执行相同操作的次数:

  • N 次:这可以通过使用RetryWaitAndRetry生成器方法来实现
    • 无限 * 次:这可以通过使用RetryForeverWaitAndRetryForever生成器方法来实现

如果要在给定的时间范围内执行重试尝试,则需要将“重试”和“超时”策略结合使用。

var timeoutPolicy = Policy.Timeout(TimeSpan.FromMinutes(4.5));
var retryPolicy = Policy
      .Handle...
      .WaitAndRetryForever(...);
var combinedPolicy = Policy.Wrap(timeoutPolicy, retryPolicy);

请记住,Wrap方法参数的顺序很重要:

  • 超时,重试:这里的超时是全局的,这意味着它覆盖所有重试尝试
  • 重试,超时:这里的超时是本地的,这意味着它分别应用于每次重试尝试

这种灵活性允许您定义每次重试尝试以及总时间约束

var globalTimeoutPolicy = Policy.Timeout(TimeSpan.FromMinutes(4.5));
var perAttemptTimeoutPolicy = Policy.Timeout(TimeSpan.FromSeconds(5));
var retryPolicy = Policy
      .Handle...
      .WaitAndRetryForever(...);
var combinedPolicy = Policy.Wrap(globalTimeoutPolicy, retryPolicy, perAttemptTimeoutPolicy);

我希望这些例子能帮助你解决你的问题。

相关问题