【发布时间】:2021-02-19 09:40:31
【问题描述】:
1 我有一个由 Js 客户端触发到 Asp.Net Core SignalR Hub 的长任务(300 万)
效果很好:
public class OptimizerHub : Hub, IOptimizerNotification
{
public async Task Optimize(LightingOptimizationInput lightingOptimizationInput)
{
LightingOptimizer lightingOptimizer = CreateLightingOptimizer();
Task t = lightingOptimizer.Optimize(lightingOptimizationInput);
await t;
}
}
2 服务器回调客户端通知进度、消息、...
Clients.Caller.SendAsync(nameof(OnProgress), progress);
到目前为止一切正常。
3 我希望通过客户端调用 Hub 方法可以取消任务
public Task Cancel()
{
GetContextLightingOptimizer()?.Cancel();
return Task.FromResult(0);
}
4 问题
当客户端进行调用时,我在 Chrome 开发者工具详细信息中看到它转到了服务器。 在 end long 任务结束 (3mn) 之前调用不会到达服务器!
5 我尝试了很多解决方案
就像改变我的长任务调用方法,总是失败:
// Don't wait end of task, fails because the context disappear and can't call back the client :
// Exception : "Cannot access a disposed object"
public async Task Optimize(LightingOptimizationInput lightingOptimizationInput)
{
LightingOptimizer lightingOptimizer = CreateLightingOptimizer();
Task t = lightingOptimizer.Optimize(lightingOptimizationInput);
}
6 种可能的解决方案
我现在想的唯一解决方案是客户端在 Http 控制器中进行 Http 调用,并传递连接 ID 这可能会导致取消。
该帖子提供了有关可能解决方案的信息: Call SignalR Core Hub method from Controller
7 个问题
是否有一种简单的方法可以让客户端在处理第一个呼叫时向集线器发出第二个呼叫?
还有一篇关于并发调用的帖子: SignalR multiple concurrent calls from client
我应该从上一篇文章中推断出即使我的中心服务器方法可以多次调用客户端,它也无法处理来自客户端的任何其他调用?
【问题讨论】:
-
也许将您的长期任务转移到Hangfire 之类的地方,让您的信号员呼叫时间缩短?
-
您在服务器端长期运行的操作是否提供了许多取消操作的好时机?
-
您误用了集线器。集线器应该是调解者,而不是主力,总之不要这样做。 .通过消息或直通将呼叫转移到有状态且适合运行长时间运行的任务。在该环境中创建取消令牌,使用字典并在必要时传回密钥,如果可用则通过其密钥取消该令牌
-
感谢您的帮助,实际上,有一个单独的类处理长调用。另一个类中需要 HubContext 来通知客户端
-
@Caius 是的,有很多美好的时刻,因为我有一个包含许多迭代的循环,并且我已经在扫描 CancellationToken
标签: c# asp.net-core task signalr-hub asp.net-core-signalr