不管是一般发送端口或是web类型的发送端口,一旦接收到NACK消息,Orchestration抛出异常后,如果没有设置scope捕获异常并处理,将导致Orchestration服务实例被挂起。
这样挂起的Orchestration服务实例是否可恢复呢?
如果Orchestration没有设置Exception Handler,发送端口的失败会导致两个挂起的服务实例:一个是发送端口的服务实例,一个是Orchestration的服务实例。
下面分别测试一下两种发送端口在未设置scope挂起后是否能被恢复。
一般的发送端口,发送一条数据插入到sql server,如果是因为插入了重复键导致了发送消息失败,将产生两个挂起的服务实例。
Figure 3. 物理发送端口出错后产生的两个挂起的服务实例
图中上面一个Messaging类型的服务就是sql的发送端口服务实例。
下面那个是Orchestration服务实例。
在sql server把重复键的那条记录删除后,测试是否可以恢复这两个服务实例。分别在两个服务实例上点击右键,选“Resume Instance”。
测试发现:
sql的发送端口服务实例可以被恢复,恢复后数据被写入数据库,挂起的sql的发送端口服务实例完成,不再挂起。
Orchestration服务实例进行恢复后,依然抛出同样的错误,服务实例再次被挂起。不管恢复多少次Orchestration,总是会抛出同样的异常。
经过测试,web类型的发送端口错误导致刮起的Orchestration,跟一般端口错误导致挂起的Orchestration一样,也是发送端口在外部条件恢复后可以resume,Orchestration却不再能resume。
测试结果:
似乎有这样的规律,orchestration收到了NACK的消息导致挂起,这样挂起的orchestration都不能恢复。
分析原因可能是因为第一个NACK消息已经被Orchestration接收,再次resume运行Orchestration,这个NACK消息再次导致Orchestration抛出异常,所以,不管恢复多少次Orchestration,总是会抛出同样的异常。
不知道是否有什么方法能把这个NACK消息从挂起的Orchestration实例中去掉?
从上面的测试可以看到,一旦发送端口返回了NACK后,即使导致发送端口出错的外部条件恢复后,发送端口可以resume,但是挂起的Orchestration再也不能恢复了。
下面设计一个处理这种情况的方法。
设计一个简单场景,Orchestration从A系统接收消息,做必要的转换后,把消息通过Port_ConsumeWS web端口发送到Web services,Orchestration接收到WS返回的消息,把返回消息通过Port_2端口发送到B系统。
Figure 4. 发送端口出错后Orchestration异常处理
发送形状设置scope用以捕获发送端口返回的异常。
Exception Handler的Exception Object Type 设置为System.Web.Services.Protocols.SoapException(可能需要引用System.Web.Services.dll程序集)。
Exception Handler的Exception Object Name设置为e,表示捕获到的一场对象。
在ConstructMessage_2消息构造形状中构造一个反映SoapException异常的消息Message_Fault(XmlDocument类型的消息)。
Message_Fault = new System.Xml.XmlDocument();
Message_Fault.LoadXml(e.Detail.InnerXml);
e.Detail.InnerXml 就是NACK的消息实际内容。
最后把这个NACK消息返回给A系统,告诉A系统发送消息失败。这个Orchestration然后正常结束。
A系统接到失败消息后,可以在系统内部设计一个机制,比如间隔一定时间后,再次发送同样的消息。
前面Orchestration异常处理后,Orchestration把失败消息发送到A系统,之后Orchestration正常结束了。但是发送端口返回NACK后,物理发送端口本身也被挂起,如果不加处理,挂起的发送端口服务实例一直会被挂着,可以通过路由失败消息的机制把发送端口失败的消息路由到某一个文件夹,作为垃圾收集站,同时消除里挂起的发送端口实例。
需要允许发送到web services的SOAP发送端口导致的失败消息可以路由。
在biztalk administrator中查看这个物理端口的属性,然后在Transport Advanced Options 中设置“Enable routing for failed messages”。
Figure 5. 发送端口设置为允许路由失败的消息
在biztalk administrator中新建一个File的发送端口,用来订阅失败的消息,都发送到一个文件夹。
设置发送端口的属性。
设为File类型的发送端口,路径指向设置好的文件夹。
端口的Filters设置如下:
Figure 6. 收集失败消息发送端口的订阅设置
Filter属性用来定义发送端口订阅消息的条件。
ErrorReport.ErrorType == FailedMessage And
ErrorReport.OutboundTransportLocation == http://biztalkr2:81/WSTest/Service1.asmx
这样的条件表示发送端口订阅失败的消息,并且是发往“http://biztalkr2:81/WSTest/Service1.asmx”的失败消息。
通过异常处理和路由失败消息,可以把发送端口产生异常导致的服务实例的挂起进行处理,结果是源系统可以获得消息未被成功发送的通知,从而可以采取相应的处理办法,或者定时重发,或者通过别的渠道处理消息等等。biztalk这边异常被处理,挂起的服务也都得到处理。
如果在发送形状前面还有业务流程并产生了作用,捕获异常后可能还需要做相应的补偿,这里没有讨论补偿的问题。
另外,这个方案应该不是最佳方案,因为A系统已经把消息发送到biztalk系统,如果在导致异常的外部条件已经恢复后,能够在biztalk这个部分就能实现resume那是最理想的。