当我开始使用 InterSystems IRIS,尤其是在互操作性方面时,我最初遇到的一个常见问题是:如何在间隔时间或计划内运行某项功能?在本专题中,我想分享两个简单的类来解决这个问题。我很惊讶在 EnsLib 的某个地方没有找到类似的类。也许是我搜索得不好?总之,这个主题并不意味着是复杂的工作,只是为初学者提供了几个片段。
假设我们有一项任务是"从 API 获取数据并将其放入外部数据库"。要完成这项任务,我们需要
Ens.BusinessProcess,其中包含我们数据流的算法:如何准备获取数据的请求,如何将 API 响应转换为数据库请求,如何通过数据流生命周期处理错误和其他事件
EnsLib.REST.Operation 用于使用 EnsLib.HTTP.OutboundAdapter 向 API 提出 HTTP 请求
Ens.BusinessOperation 与 EnsLib.SQL.OutboundAdapter,用于通过 JDBC 连接将数据输入外部数据库
关于这些业务主机的实现细节不在本文讨论范围之内,我们假设已经有了一个进程和两个操作。但如何运行这一切呢?进程只能通过入站请求运行......我们需要一个启动器(Initiator)!我们需要一个启动器!这个启动器将通过间隔运行,并向我们的进程发送一个虚假请求。
下面就是这样一个启动器类。我添加了一些额外的功能:使用同步或异步调用,如果有许多主机作为目标,可以在出错时停止或不停止进程。但这里主要是一个目标列表。我们将向列表中的每个项目(业务主机)发送请求。请注意 OnGetConnections 事件——它是在生产用户界面中正确建立链接所必需的。
Class Util.Service.IntervalCall Extends Ens.BusinessService
{
Property TargetConfigNames As Ens.DataType.ConfigName
Property AsyncCall As %Boolean
Property BreakOnError As %Boolean [ InitialExpression = 1 ]
Property Adapter As Ens.InboundAdapter
Parameter ADAPTER = "Ens.InboundAdapter"
Parameter SETTINGS = "TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},AsyncCall,BreakOnError"
Method OnProcessInput(pInput As %RegisteredObject, Output pOutput As %RegisteredObject, ByRef pHint As %String) As %Status
{
Set tSC = $$$OK
Set targets = $LISTFROMSTRING(..TargetConfigNames)
Quit:$LISTLENGTH(targets)=0 $$$ERROR($$$GeneralError, "TargetConfigNames are not defined")
For i=1:1:$LISTLENGTH(targets) {
Set target = $LISTGET(targets, i)
Set pRequest = ##class(Ens.Request).%New()
If ..AsyncCall {
Set tSC = ..SendRequestAsync(target, pRequest)
} Else {
Set tSC = ..SendRequestSync(target, pRequest, .pResponse)
}
Quit:($$$ISERR(tSC)&&..BreakOnError)
}
Quit tSC
}
ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item)
{
If pItem.GetModifiedSetting("TargetConfigNames", .tValue) {
Set targets = $LISTFROMSTRING(tValue)
For i=1:1:$LISTLENGTH(targets) Set pArray($LISTGET(targets, i)) = ""
}
}
}
之后,您只需将该类添加到生产中,并在 TargetConfigNames 设置中标记我们的业务流程。
但如果需求发生了变化怎么办?现在我们需要每周一上午 08:00 运行数据抓取器。最好的办法是使用任务管理器(Task Manager)。为此,我们需要创建一个自定义任务,以编程方式运行启动器。下面是该任务的简单代码:
Class Util.Task.ScheduleCall Extends %SYS.Task.Definition
{
Parameter TaskName = "Launch On Schedule"
Property ServiceName As Ens.DataType.ConfigName
Method OnTask() As %Status
{
#dim tService As Ens.BusinessService
Set tSC = ##class(Ens.Director).CreateBusinessService(..ServiceName, .tService)
Quit:$$$ISERR(tSC) tSC
Set pRequest = ##class(Ens.Request).%New()
Quit tService.ProcessInput(pRequest, .pResponse)
}
}
这里有两件重要的事情:
- 您必须将 Initiator 业务服务的
Pool Size 设置为 0,以防止通过调用间隔运行它(选项 Call Interval,您可以清除或保持原样——当 Pool Size 为 0 时,它不会被使用)。

- 您需要在
Task Manager 中创建一个任务,选择"Launch On Schedule" 作为任务类型(不要忘记选中命名空间),将我们的启动程序业务服务名称设置为 ServiceName 参数,并设置所需的日程。请参阅:System Operation > Task Manager > New Task
奖励
我经常遇到这样的情况:我们需要在生产中按需运行某些功能。当然,我们可以为此在 CSP 上创建一些自定义用户界面,但重新发明轮子不是我们的办法。我认为最好使用管理门户(Management Portal)的典型用户界面。因此,我们之前创建的任务也可以手动运行。只需将任务运行类型更改为 On Demand。按需任务列表可在 System > Task Manager > On-demand Tasks,请参见 Run 按钮。此外, Run 按钮(手动运行)可用于任何类型的任务。
就是这样。现在,我们的业务主机有了一个漂亮的互操作性架构。还有 3 种运行数据采集器的方式:按时间间隔、按时间表或手动。