文章目录
第二十七章 开发Productions - ObjectScript Productions - 定义业务流程 - 关键原则
关键原则
在开发业务流程时,请考虑以下关键原则:
- 有时希望使响应对象成为传入请求对象的修改版本,分阶段进行修改可能很有用。但是,不要修改传入的请求对象。而是将其复制到上下文变量(或者,对于自定义业务流程,将数据复制到局部变量)。然后修改副本。
- 同步发送消息时要小心(只能在自定义业务流程中或
BPL
中的<code>
中执行)。
当业务流程A
同步调用业务流程B时,流程A不会继续,直到收到响应。如果进程 A
需要完成对其他进程 (B
) 的调用才能完成自身,并且如果这些进程共享参与者作业池,则如果没有空闲的参与者作业来处理被调用的业务流程,则参与者池可能会陷入死锁( B
).
发生这种情况是因为在被调用业务流程返回之前,调用业务流程无法完成并释放参与者作业,但被调用业务流程无法执行,因为没有空闲的参与者作业来执行它。
另请注意, IRIS
无法在真正的同步调用期间关闭。
最好使用 SendRequestAsync()
并在 OnResponse()
方法中处理响应消息。如果需要同步调用,可以通过配置被调用的业务流程(B
)使用自己的作业池来避免这个问题。
- 如果单一作业业务流程发出请求并等待响应,则该流程将失去
FIFO
功能。
因为来自 BPL
的同步调用是由编译器异步实现的,所以业务流程将在发出调用后转到磁盘。然后,参与者可以继续使新的业务流程或对其他业务流程的响应出队。
如果没有发出需要响应的调用请求,则仅保证单个作业业务流程的 FIFO 处理。如果业务流程必须进行调用并仍保持 FIFO
,则它必须使用调用 SendRequestSync()
的 <code>
活动。但是,在这种情况下,前面的项目符号项目适用。
- BPL 提供了一个有用的优势:它以流线型和优雅的方式处理同步和异步消息传递的各个方面,从而防止常见的争用和死锁问题。即使调用被标记为同步,如果需要任何等待时间,生产框架也会安静地释放代表
BPL
业务流程执行调用的作业,以便它可以在BPL
等待同步响应时执行其他工作。稍后,框架静默协调同步响应的接收并唤醒 BPL 业务流程以恢复其工作。
如果使用自定义代码,很容易(不小心)设计出容易出现死锁的产品。需要做的就是创建一系列发送同步请求并使用有限参与者池的业务流程。如果 production
随后接收到与 actor
相同数量的消息,并且所有消息同时发生同步发送,则 production
最终陷入死锁,所有 actor
进程都处于等待另一个进程从队列中释放消息的状态.此问题最危险的方面是测试不一定会产生导致死锁的条件。很有可能在部署后首先遇到死锁。目前尚不清楚生产中断的原因,而且这一不可预见的问题的成本可能很高。
定义 BPL 业务流程
BPL
业务流程是基于 Ens.BusinessProcessBPL
的类。在这种情况下,可以在管理门户或 IDE
中可视化地创建和编辑流程。有关信息,请参阅开发 BPL
流程。
定义自定义业务流程
要创建自定义业务流程类,请按如下方式定义一个类:
- 类必须在(或子类)中扩展
Ens.BusinessProcess
。 - 类必须实现
OnRequest()
和OnResponse()
方法,如下两节所述。 - 班级可以添加或删除设置。请参阅添加和删除设置。
- 类可以实现任何或所有启动和拆卸方法。请参阅覆盖启动和停止行为。
- 类可以包含完成自身内部工作的方法。
实现 OnRequest()
方法
自定义业务流程类必须实现 OnRequest()
方法。每当对特定业务流程的初始请求到达适当的队列并分配一个要执行的作业时,生产就会调用此方法。
此方法具有以下签名:
method OnRequest(request As %Library.Persistent, Output response As %Library.Persistent) as %Status
request
— 传入的请求对象。response
— 此业务流程返回的响应。
示例
以下是 OnRequest()
方法的示例:
Method OnRequest(request As Demo.Loan.Msg.Application, Output response As Demo.Loan.Msg.Approval)
As %Status
{
Set tSC=$$$OK
$$$TRACE("received application for "_request.Name)
#;
If $zcrc(request.Name,2)#5=0 {
Set tRequest = ##class(Demo.Loan.Msg.PrimeRateRequest).%New()
Set tSC =..SendRequestAsync("Demo.Loan.WebOperations",tRequest,1,"PrimeRate")
If $$$ISOK(tSC){
Set tRequest = ##class(Demo.Loan.Msg.CreditRatingRequest).%New()
Set tRequest.SSN = request.SSN
Set tSC =..SendRequestAsync("Demo.Loan.WebOperations",tRequest,1,"CreditRating")
If $$$ISOK(tSC){
Set tSC = ..SetTimer("PT15S")
}
}
} Else {
Set response = ##class(Demo.Loan.Msg.Approval).%New()
Set response.BankName = "BankUS"
Set response.IsApproved = 0
$$$TRACE("application is denied because of bank holiday")
}
Return tSC
}
实施 OnResponse()
方法
自定义业务流程类必须实现 OnResponse()
方法。每当特定业务流程的响应到达适当的队列并分配一个要执行的作业时,生产就会调用此方法。通常,这是对业务流程发出的异步请求的响应。
method OnResponse(request As %Library.Persistent,
ByRef response As %Library.Persistent,
callrequest As %Library.Persistent,
callresponse As %Library.Persistent,
pCompletionKey As %String) as %Status
request
— 发送到此业务流程的初始请求对象。response
— 此业务流程最终将返回的响应对象。callrequest
— 与传入响应关联的请求对象。callresponse
— 传入响应对象。pCompletionKey
— 与传入响应关联的完成键值。这是通过调用发出请求的SendRequestAsync()
方法设置的。
示例
以下是 OnResponse()
方法的示例:
/// Handle a 'Response'
Method OnResponse(request As Ens.Request,
ByRef response As Ens.Response,
callrequest As Ens.Request,
callresponse As Ens.Response,
pCompletionKey As %String) As %Status
{
Set tSC=$$$OK
If pCompletionKey="PrimeRate" {
Set ..PrimeRate = callresponse.PrimeRate
} Elseif pCompletionKey="CreditRating" {
Set ..CreditRating = callresponse.CreditRating
}
Return tSC
}
在 OnRequest()
和 OnResponse()
中使用的方法
SendDeferredResponse()
SendRequestSync()
SendRequestAsync()
SetTimer()
IsComponent()