我正在开发一个 API,它接收消息并将它们以 .json 格式上传到 SFTP 服务器。但是,连接时间太长了,SFTP连接需要1秒多,太多了。 想知道有没有什么办法不用等那么久就可以连上服务器发送文件了
我想过保存文件,回答客户,然后用这个方法上传文件:
public async Task Upload(string localPath, string remotePath)
{
await Task.Run(() =>
{
// upload code here
});
}
但是,如果上传过程中出现异常,API可能已经向客户端响应了OK,导致无法通知客户端上传失败。
这是我目前用来上传文件的现有代码:
public void Upload(string localPath, string remotePath)
{
try
{
using (var sftp = new SftpClient(...))
{
sftp.Connect(); // Very slow
sftp.UploadFile(...);
sftp.Disconnect();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error Upload SFTPHandler");
}
}
有人可以建议一个连接到 SFTP 服务器并发送文件而无需等待这么久的解决方案吗?
您可以存储上传状态,并单独检查是否已上传。例如,您可以将状态缓存在
ConcurrentDictionary
中。然后客户端可以定期轮询上传状态。
假设你使用的是 SSH.Net 客户端,你也可以使用它的异步方法。
static ConcurrentDictionary<string, bool> _statuses = new();
[HttpPost]
public async Task UploadFile(string localPath, string remotePath)
{
_statuses[remotePath] = false;
Task.Run(() => Upload(localPath, remotePath));
}
private async Task Upload(string localPath, string remotePath)
{
try
{
using var sftp = new SftpClient(...);
sftp.ConnectAsync();
await TaskFactory.FromAsync(
(input, path, asyncCallback, state) =>
sftp.BeginUploadFile(input, path, asyncCallback),
sftp.EndUploadFile,
..., // some filestream
remotePath,
null);
_statuses[remotePath] = true;
sftp.Disconnect();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error Upload SFTPHandler");
}
}
[HttpPost]
public async Task<bool> IsUploaded(string remotePath)
{
if (!_statuses.TryGetValue(remotePath, out var value))
{
// IIS was restarted.
// check SFTP for finished upload.
_statuses.Add(someStatus);
}
return value;
}
您可能需要考虑在 IIS 服务器重新启动时缓存状态的某种方式。
但是,如果上传过程中出现异常,API可能已经向客户端响应了OK,导致无法通知客户端上传失败。
所有“即发即弃”的工作都是如此,这就是为什么它通常是错误的解决方案。
如果您绝对不能等待超过 1 秒(??对我来说听起来并不太不合理),那么您最好的选择是 基本分布式架构,如我的博客所述。基本的分布式架构有两部分,还有一个可选的第三部分(这听起来像你想要的):