实现对长时间运行的服务器端方法的客户端调用的正确方法

Posted

技术标签:

【中文标题】实现对长时间运行的服务器端方法的客户端调用的正确方法【英文标题】:Correct way to implement a client-call to a long running server-side method 【发布时间】:2017-01-22 00:02:19 【问题描述】:

我正在使用 WCF 中的 SOAP 客户端与自托管的 WCF 服务进行通信,以远程控制我正在开发的软件。这个软件有一个运行时间很长的操作(我们称之为Print),它会运行几分钟,可能长达一个小时。我试图弄清楚如何在满足以下要求的情况下实现 Print 方法:

    服务器应该能够向客户端提出FaultExceptions,以防出现问题。 如果与服务的连接丢失,应尽快通知客户端。 如果断开连接,Print 的服务器端进程应该继续运行,以便客户端可以重新连接并继续监视该进程并在必要时中止它。

由于我是 WCF 新手,我不确定如何实现这一点。我目前看到两种选择:

    使Print 成为async 方法,这样我就可以“触发并忘记”它,直到它完成或抛出FaultException。这看起来很简单,但我看到了这个“问题”:WCF 中有一个客户端请求超时,默认值为 1 分钟,这也适用于 async 方法(如果我没记错的话),我会因此必须大幅增加。这看起来有点像 hack。 自己实现Printasync 行为,方法是将其行为拆分为-async 方法StartPringing,该方法启动服务器端打印任务并直接返回(或在出现问题时抛出异常)和客户端回调方法PrintingFinished。然后我可以使用回调PrintingFinished 向客户端发出信号,当打印过程完成时,或者使用额外的回调PrintingFailed 发送异常以防出现问题。此实现将“隐藏”在async 方法Print 后面,因此它的行为与可能引发异常的任何其他async 方法一样。在这里我看到了以下挑战:我必须自己实现整个异常回调的东西,以处理StartPringing 返回后发生的异常(从StartPringing 本身我可以抛出FaultExceptions)。

对于这两种情况,我都必须弄清楚如何检测连接何时提供服务(我目前正在使用服务上的 ping 方法),然后以某种方式让该事件从方法 @ 中引发异常987654341@。在实现方面,这似乎更符合备选方案 (2),因为我需要已经实现所有其他事件处理程序,以便在打印过程完成或引发异常时。但是,我不确定如何为替代方案 (1) 实现此功能。

那么这两种选择中的哪一种“更好”。更好是指以下考虑因素: 1. 与 WCF 中的“标准”方式保持一致,用于实现这种长时间运行的方法。 2. 可维护性和可扩展性。

如果我应该考虑任何其他选择,我将不胜感激任何其他建议。

【问题讨论】:

【参考方案1】:

就我对您的问题的理解而言,我认为如果您需要可靠的真正异步通信来使用像 MSMQ 这样的消息队列。您可以将它与 WCF 一起使用:https://msdn.microsoft.com/en-us/library/ms789048(v=vs.110).aspx

更新

在您的情况下,您可以使用 SOAP 调用将打印命令发送到服务器,因为它同步并且您需要知道服务器是否处理请求。在打印操作之后是长且异步的。当此操作完成(异常与否)时,它需要通知客户端。但是例如,客户端可能会被关闭。对于该通信,消息队列是解决方案,MQ 确保消息将被传输。 https://en.wikipedia.org/wiki/Message_queue

如果您不想使用 MSMQ,您可以在客户端实现 Web 服务以接收打印服务器的通知,例如使用 UUID 来匹配内存或数据库中地图中的调用和通知。

【讨论】:

感谢您的回答。您能否详细说明一下,为什么您认为我需要 MSMQ?我的印象是 WCF 中的请求被传输,如果不是,我会得到某种通信异常。进一步详细说明我的实现:我正在使用 net.tcp 绑定,所有通信都将在本地网络上进行。我不知道 MSMQ(而且我是 WCF 的新手),但 MSMQ 通信似乎还有很多工作要做。我想采用一种真正符合 KISS 原则的方法,因为我只有一个长期运行的方法(如有必要,请忘记我问题的可扩展性部分)。 只是为了扩展我的评论以及我犹豫的原因:我已经使用 net.tcp 绑定解决了大部分实现细节。 “唯一”缺失的(当然是大的)部分是我在我的问题中详述的方法的实现。所以这就是为什么我在没有充分理由的情况下不愿切换绑定的原因。很高兴听到您的意见... 感谢您更新答案。因此,假设我在开始打印过程后要跳过async 部分。我的想法是让Print 方法在连接丢失时抛出“断开连接”异常。然后客户端的工作就是重新连接到服务并检查打印设备的状态(即“打印”是否仍在运行或完成)。我已经预见到诸如“打印机活动状态”之类的属性,客户端的用户可以使用这些属性来检查打印机的状态并在重新连接后采取相应的行动。在这种情况下,我不需要 MSMQ,对吗? 是的,一个解决方案可能是:客户端延迟拉取服务器的状态。无需等待异常:1 次调用以启动打印(服务器只是释放并使用另一个线程)并在拉动状态服务之后。 有很多方法可以实现您想要的,但最好的方法是使用消息队列。

以上是关于实现对长时间运行的服务器端方法的客户端调用的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

将 NWConnection 用于长时间运行的 TCP 套接字的正确方法

用于长时间运行过程的 Spring SSE

超时服务器端长时间运行的请求[重复]

如何使用 .Net 库管理对 Snowflake 的长时间运行过程调用

当应用程序后台运行时,Objective-c 长时间运行的蓝牙后台服务

ssh长时间连接腾讯云centos服务器