问题描述:
在Biztalk项目开发过程中碰到在Orchestration中从WebService Port抛出一个异常并导致实例挂起后,即使修复了WebService的异常,我们仍然无法恢复Orchestration对应的消息实例
通过向微软全球技术中心的专家咨询,已明确前期异常测试过程中发现的Biztalk无法恢复WebService异常所导致的消息实例被挂起的现象是一个已知的问题,是在设计时就决定的。所有request/response的双向端口都不适合用此种方式直接恢复流程。具体方案见下:
1. Biztalk WebService 异常问题描述
问题场景:
两个由DMS 向I-CROP 发起的相关业务:
A. 服务委托书
B. 派工单
由于I-CROP 如果先接收B 后接收A 后会出错,而目前方案采用的是一个业务一个Queue 的并行方式,所以只能由DMS 端将两个相关业务合并为一个大报文,并由Biztalk 拆分成两部分后分别提交
三个消息对象
A. 服务委托书
B. 派工单
C. 预约ID
三个业务流程
a. 主流程
b. 服务委托书子流程
c. 派工单子流程
两个业务Queue
1. 服务委托书和派工单的大报文Schema Queue
2. 派工单单独的Schema Queue
业务步骤:
1.Biztalk 从DMS Queue 中获取A. 服务委托书 B. 派工单两部分的一个大报文;
2. 拆分A. 服务委托书 B. 派工单两个消息;
3. 通过SOAP Adapter 向I-CROP 发出A. 服务委托书( 通过Call Orchestration 调用b 流程) ;
4.Biztalk 通过上述Web Service 的返回值得到预约ID ;
5.Biztalk 将预约ID 送回DMS ;
6.Biztalk 通过SOAP Adapter 向I-CROP 发出B. 派工单;( 通过Call Orchestration 调用c 流程)
7.Biztalk 将B. 派工单的Web Service 返回状态存入备份File Port ;
问题描述:
当网络断开时,在挂起中可以查看到消息和流程两个都被挂起,但网络恢复后,消息可以手动被重新提交到Web Service 成功接受,但是由于SOAP 是一个双向Port ,预约ID 无法被再次接入 流程无法恢复( 通过跟踪发现流程中止于A. 服务委托书的方法返回上,即预约ID 的接收) ,致使该笔业务的两个部分无法被完整送达。
2. 微软开发组内部资源文档翻译摘要
错误描述:
从WebService抛出一个异常并导致实例挂起后,即使修复了WebService的异常,我们仍然无法恢复Orchestration对应的消息实例
期望输出:
当修复了由WebService引发的异常时,我们期望两个实例(指Messaging和Orchestration)都能够恢复运行,并且Orchestration不会被再次挂起
重要提示:
从开发组得到的官方答复是,这不是一个Bug,而是设计时决定的.
如果客户需要以正确方式解决这个问题,他们需要实现错误捕捉和处理
内部机制:
-Orchestration发送消息到WebService.此时会创建一个状态提交点(state commit point).
-WebService抛出异常,这个异常(SOAP fault)被队列化到实例中.
由于异常没有被捕捉,实例就会被挂起.
-当我们试图去恢复这个实例时,只是恢复了发送状态之后的部分,而状态提交点无法被恢复.
因为还有一个应答错误(NACK),这导致了重新回到Orchestration的实例被再一次挂起.
开发建议:
可按以下伪代码,修改Orchestration来解决这个问题:
bool continue = true;
while(continue)
{
Send-message(); // Request message
Scope
{ // Transaction=None
receive(); // response message
continue = false; // Everything went well, no need to repeat
}
catch(Exception)
{
Suspend();
}
}
3. 微软建议方案一
首先可以通过将Retry Count和retry interval设为教大的数字以应对多数情况下的网络暂时中断,因为本文讨论的问题,只有在超出Retry Count后才会发生(具体设置数值需根据部署环境和网络情况酌情决定),这样,短时间的网络异常就不会导致流程的挂起;
通过Scope /Catch Exception机制在Orchestration的Catch部分捕捉相应的错误;
如发生错误时,从消息上下文确定重试次数和重试间隔,如超出重试次数后将发生错误的源消息写入备用Port(backup transport)并记录和通知这个错误(可考虑开发能邮件提醒的功能);
开发一个外部人工操作的工具,负责将数据从备份端口读回,写回到数据发送的初始Queue中。
此方案在网络出错时,需要进行人为干预,需要确定维护负责人选。
4. 微软建议方案二
通过Scope /Catch Exception机制在业务步骤3中捕捉SOAP错误,在错误处理代码中,将消息大报文写回到DMS Queue AB两大部分的Queue中,并等待a.主流程 的再次调用,流程就此结束;
如在业务步骤6中捕捉到SOAP错误,在错误处理代码中,将B.派工单消息写回到DMS Queue B.派工单Queue中,并等待c.派工单 流程Orchestration 的再次调用,流程就此结束;
此方案在网络出错时不需要人工干预,但是在一段时间内数据会不断地重试,形成短时间内的死循环。
注:此方案需要在SOAP Send Port配置时设置以下参数:
Retry Count 0
Ordered delivery checked
Stop sending subsequent messages on current message failure checked
Enable routing for failed message checked