#互操作性

0 关注者 · 67 帖子

在医疗保健领域,互操作性是指在不同信息技术系统和软件应用程序之间进行通信、数据交换以及使用交换信息的能力。

文章 Hao Ma · 五月 31, 2021 6m read

HealthConnect中创建HTTP服务端

这里我说说怎么在HealthConnect上开发HTTP服务。

作为消息引擎,HealthConnect会需要从一个接口接收HTTP请求发送到另一个接口,中间做消息转换,路由等等,目的的接口可能是HTTP,或者SOAP,REST等等。这里只介绍HTTP服务的内容,也就是最简单的两种实现:

第一种:实现客户定制的HTTP服务业务服务组件(Business Servie)

创建Business Service类,继承EnsLib.HTTP.Service, 如下面的示例:

Class SEDemo.IO.HTTP.ServiceExample1 Extends EnsLib.HTTP.Service
{
    Parameter ADAPTER;
    Method OnProcessInput(pInput As %Stream.Object, Output pOutput As %Stream.Object) As %Status
    {
        //创建Ensemble消息发送给其他组件
        set pRequest=##class(Ens.StreamContainer).%New()
        Set tSC=pRequest.StreamSet(pInput)
        set tSC= ..SendRequestAsync("Dummy1",pRequest,.pResponse)
        //创建返回Stream,发送给调用方
        set pOutput=##class(%Stream.GlobalCharacter).%New()
        do pOutput.Write("yes, I recieved request")
        Quit tSC
    }
}

详细说明:

使用CSP机制接收请求,不要用HTTP的Inbound Adpater,这样能得到

如果您学习过在Ensemble上开发SOAP接口,一定对代码里的***"Parameter ADAPTER;"***不陌生,它的作用是确定不要使用父类里的Adapter。

EnsLib.HTTP.Service有两个工种模式,一个是使用内置适配器是Ens.HTTP.InboundAdapter,还有一个是使用CSP机制,从CSP Gateway接收请求。下面的图中黄色的箭头是用适配器接收消息,这时业务服务可以定义工种的URL,端口,SSL等等;下面红色的箭头是所谓的”CSP请求“,也就是HTTP请求经过Web服务器,CSP Gateway, 到Web Application, 再被EnsLib.HTTP.Service收到。

使用CSP机制有更好的安全性和性能,所以在HealthConnect中任何HTTP的服务端接口我们都推荐CSP机制,包括HTTP接口,SOAP接口, REST接口。这些接口的开发都不要使用对应的InboundAdapter。

有关CSP Gateway的原理,还可以参见在线文档或者我的另一技术文章:Web Gateway介绍

注意的是:当不使用Adapter时,Production页面的组件配置中很多项目会消失,这些是Adapter的属性,比如允许的IP, 端口,包括编码等等。因为不用Adapter,您也不用定义IP,端口号;只有编码,可以在BS的代码里实现。实现的操作可以参考Adapter的设置: https://docs.intersystems.com/healthconnectlatest/csp/docbook/Doc.View.cls?KEY=EHTTP_settings_inbound

OnProcessInput()的入参pInput

业务组件收到的HTTP请求由pInput传入,真正的类型是%CSP.GlobalBinaryStream,它的父类是已经不推荐使用的流类型%GlobalBinaryStream。用%Stream.Object作为pInput的对象类型是合适的,这是一个新版本的Stream对象的超类,可以是任意类型的流。上面代码里业务服务组件发出的Ensemble消息的类型是StreamContainer,如果你看看消息跟踪的类型,你会发现里面流的类型是”GB",也就是一个%GlobalBinaryStream类型的流。

pInput对象的属性Stream里存放的是HTTP Body,而HTTP头放在Attributes属性里,如下图所示:

如何获得请求里的消息头

以下是用pInput.GetAttributeList()得到的Attributes的内容:

 <![CDATA[*CSPApplication/csp/healthshare/demo/CharEncoding1EnsConfigName SEDemo.IO.HTTP.ServiceExample1
        HTTPVersion1.1
        HttpRequestGET
            IParamsParamsRawParamsTranslationTableRAWAURL:/csp/healthshare/demo/SEDemo.IO.HTTP.ServiceExample1.clsaccept*/*"accept-encodinggzip, deflatecache-control
        no-cacheconnectionkeep-alivecontent-length0content-type£cookieCSPSESSIONID-SP-80-UP-csp-healthshare-=0000010100002ROlNxwgxwUQuPHKQogHGNWfADLfF2xiPwce2s; CacheBrowserId=ui$4lIZ_rJsPD_xUTPG$Rw; CSPWSERVERID=B33PnJAehost172.16.58.200mykeyimess7postman-token&83e942ce-ae73-4d98-b7ab-1e2803c95794%user-agentPostmanRuntime/7.18.0]]>

而获取消息头的某些值, 可以用 pInput.Attributes(http_header_name)得到, 比如下面这些:

    set MethodTypeName=pInput.Attributes("HttpRequest")
	set HTTPVersion = pInput.Attributes("HTTPVersion")
    set ContentType = pInput.Attributes("content-type")
    set ContentLength = pInput.Attributes("content-length")
    set URL = pInput.Attributes("URL")
    //获得GET请求,得到URL中的form参数(注意,POST请求的表单数据在消息体里面)
    set pList = Attributes("Params",form_variable_name,n), 
    //得到自定义的消息头值,比如上面的消息里面有个自定义的头字段“mykey"
    set Mykey = pInput.Attributes("mykey")

更多的细节,请参考在线文档: Using the HTTP Inbound Adap: About the Attributes Array

中文编码转码

如果请求的流里面有中文字符,需要在代码里执行转码,比如下面这个例子,把pInput的流,转码成UTF8,放到Ens.StringRequest里传输。

    set pRequest=##class(Ens.StringRequest).%New()
    set pRequest.StringValue=$ZCVT(pInput.Read(),"I","UTF8")
    set sc= ..SendRequestAsync("Dummy1",pRequest,.pResponse)

有关组件名称和访问的URL

请求的URL有两个通常的选择:

  1. Production里面的业务组件名字和类名称一样

比如上面代码的类是"SEDemo.IO.HTTP.ServiceExample1",如果production的业务服务也是同样的名字,那么调用它的URL就是

    http://hostip:port/csp/healthshare/demo/SEDemo.IO.HTTP.ServiceExample1.cls

其中"/csp/healthshare/demo/"是Web Application的名字。

  • 如果上一条不成立。比如写了一个类,用于多个业务服务组件,那么需要组件的名字可以用自己的名字,调用的URL要包含?CfgItem=xxx表示寻找不同的业务组件服务。举例说,还是上面的类,用于添加了两个业务服务组件"httpservice2"和"httpservice3",访问它们的URL就是:
    http://hostip:port/csp/healthshare/demo/SEDemo.IO.HTTP.ServiceExample1.cls?CfgItem=httpservice2
    http://hostip:port/csp/healthshare/demo/SEDemo.IO.HTTP.ServiceExample1.cls?CfgItem=httpservice3

还有这么个操作,就是单独创建一个Web Application, 配置DispatchClass,来接入一个Web服务。我觉得完全没有必要,而且新版本中Web Application的菜单里只剩下了为REST分配分派类的选择,因此这里就不说这个了。

第二种: 使用EnsLib.HTTP.GenericService预置业务服务组件

使用预置的,开发好的组件意味着不用写代码,配置一下就可以使用。相应的,灵活性上就差了,大概只适合简单的透传,转发,路由。如果要修改数据包内容,http头内容,编码转换等等,需要要在其他的组件上,比如production中消息经过的BP, BO中实现。

EnsLib.HTTP.GenericService的父类是EnsLib.HTTP.Service,因此它也是可以使用Adapter机制或者CSP标准机制。如前面所述,我们需要用CSP机制,调用的URL必须包含**?CfgItem=组件配置名**,比如我在Production里面配置了组件”GenericService1", 那么我访问的请求就应该是:

    http://localhost/csp/healthshare/demo/EnsLib.HTTP.GenericService.cls?CfgItem=GenericHTTPService1

还有,因为我们不修改代码,所以组件配置项中会有Adapter的配置,比如端口号,SSL配置,直接忽略它们,不用理睬。 。如果您看到配置项上有”字符集",显示的是UTF-8,可是没起作用,请不要奇怪,这个是Adapter的配置,您用CSP机制时它是不起作用的。

EnsLib.HTTP.GenericService向其他业务组件发出的Ensemble消息的类型是EnsLib.HTTP.GenericMessage。以下是一个POST请求被业务服务组件发送给BO的消息样例。

        <!-- type: EnsLib.HTTP.GenericMessage  id: 531 -->
        <HTTPMessage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://www.w3.org/2001/XMLSchema">
        <Stream>{
        âserial_idâ: âC20114062017025â,
        âtake_timeâ: â2019-01-02 15:04:05â,
        âpos_timeâ: â2019-01-02 15:04:05â,
        âtypeâ: â1â,
        âwarnâ: â0â,
        âfile_idâ: â9cd586eef356c71f64b82a190b469e69â,
        âfile_nameâ: âA1012014400596520160714190338.hlyâ,
        âfile_pathâ: â/service/data/TE9100Yâ,
        âbegin_timeâ: â2016-07-04 20:17:21â,
        âend_timeâ: â2016-07-04 20:18:21â,
        âlengthâ: â60â,
        âsizeâ: â9650â,
        âresultâ: â窦æ§å¿ç, æ¬æ¬¡å¿çµçæµæªè§å¼å¸¸â
        }</Stream>
        <Type>GB</Type>
        <HTTPHeaders>
        <HTTPHeadersItem HTTPHeadersKey="CSPApplication">/csp/healthshare/demo/</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="CharEncoding" xsi:nil="true"></HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="EnsConfigName">GenericHTTPService1</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="HTTPVersion">1.1</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="HttpRequest">POST</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="IParams">1</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="IParams_1">CfgItem=GenericHTTPService1</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="RawParams">CfgItem=GenericHTTPService1</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="TranslationTable">RAW</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="URL">/csp/healthshare/demo/EnsLib.HTTP.GenericService.cls</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="accept">*/*</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="accept-encoding">gzip, deflate, br</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="authorization">Basic X3N5c3RlbTpTWVM=</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="cache-control">no-cache</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="connection">keep-alive</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="content-length">532</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="content-type">text/plain</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="cookie">CSPSESSIONID-SP-52773-UP-csp-healthshare-=0000000100006fSAbXykPFTd0NFNEoaUH94y07Phmq0V92aeDg; CSPBrowserId=F4nsRY6yDGVipvQ84sDN3w; CSPWSERVERID=I33xYkI3</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="host">172.16.58.200:52773</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="postman-token">0e0bf4a7-868b-4e69-bbac-bfd89909fe99</HTTPHeadersItem>
        <HTTPHeadersItem HTTPHeadersKey="user-agent">PostmanRuntime/7.28.0</HTTPHeadersItem>
        </HTTPHeaders>
        </HTTPMessage>

使用这个组件要注意的几点:

  • 上面的数据包里有中文乱码,我是故意这么做的,就是提醒您:强调一下选用这个组件时,如果要修改数据,可以在其他的组件处理。如果我做一个简单的HTTP转发,我可以选用EnsLib.HTTP.GenericService和EnsLib.HTTP.GenericOperation这一对预置组件,这样BS,BO就免开发了。而如果中间要做中文编码的转换,我会插入一个BP, 专门处理EnsLib.HTTP.GenericMessage里的中文转码。

  • 组件的"启动标准请求"配置项:要使用CSP Gateway请求机制时应该勾选。

  • "持久消息已发送INPROC"配置项( PersistInProcData) 这个选项是专用于以InProc模式同步调用时是否要持久化Ensemble消息的选项,默认是保存。如果设置成off,那么HealthConnect即不保留消息头,也不保留消息体,在消息查看器里无法查看,也不能重传。

  • “保持标准请求分区”配置项 也是用于InProc模式调用,是否保留到BO定义的外部系统的连接。和上面的"持久消息已发送INPROC"配置项一样,很少被用到,保留默认的选中就可以。

  • "没有字符集转换”配置项 控制CSP Gateway是否对%reponse消息里的文本按content-type的类型转码,默认是不勾选,也就是保留CSP Gateway的转码功能。

  • ”One-Way"配置项 如果客户端不期待响应消息,那么选中这个选项后,EnsLib.HTTP.GenericService收到请求转发的同时会送一个Http状态码202,意思是”服务器已接受请求,但尚未处理“. 默认是不选中这个配置。

0
1 417
文章 Nicky Zhu · 五月 20, 2021 7m read

在上一篇文章《互操作消息统一管理系列:Message Bank》中,我们了解到在Message Bank中,消息均以半结构化(XML)或非结构化(Stream)的形式保存,因此无法与客户端的结构化消息一样,直接支持基于索引的检索。为此,需要在Message Bank中定义Search Table以支持查询。关于Search Table的定义和作用,请查阅https://docs.intersystems.com/healthconnectlatest/csp/docbook/DocBook.UI.Page.cls?KEY=EEDI_search_tables。

一. 在Message Bank中查询消息的特殊之处

大家如果使用过消息查看器,则能够了解IRIS自动持久化消息并提供界面让大家能够根据消息头中(如发生事件、来源、目标等)或消息体中(如患者姓名、诊断名称等消息的具体属性)来查询消息。 而在Message Bank上进行查询时,如果直接使用消息查看器,能够查询的是Message Bank的Production中传输的消息,而若不是在源系统中出现的消息,这一点一定不要混淆。 Message Bank提供了消息仓库查看器供大家查询源系统中的消息 image

查询界面尽管在风格与功能上与消息查看器非常相似,但查询的目标是在Message Bank中转储的消息(存储格式为虚拟文档或字符流,见上一篇文章)。因此,查询索引与原来的消息截然不同,需要单独创建。其中,虚拟文档在IRIS中有原生支持,我们先来看自定义消息类型的处理过程。

先看这样一个案例。

二. 测试系统

假设我们有一个REST接口实现的添加患者业务,如下所示: image

实现了REST接口,接收如下格式的POST请求,在该实例数据库中创建患者: image

注意,从外部JSON传入的报文,在经过IRIS处理的过程中,会被转换为XML格式的消息,如下: image

在被转储到Message Bank后,以同样结构的XML字符流存储 image

三. 在消息转储过程中创建索引

Message Bank中转储的消息默认是没有索引的,需要在消息转储过程中创建。

通过回调干预消息转储过程

Message Bank的Production中的服务Ens.Enterprise.MsgBank.TCPService提供了回调函数入口,使用户可以在消息转储过程中执行自定义的逻辑实现需求。因此,可用于触发对Search Table索引的建立过程。 要定义回调函数,则需要继承类Ens.Enterprise.MsgBank.BankHelperClass,并实现方法OnBankMsg,如下所示:

Class MessageBank.MsgSerializationHelper Extends Ens.Enterprise.MsgBank.BankHelperClass [ Language = objectscript ]
{

/// 参数IndexClassList用于指定将被该回调函数索引的(客户端)消息类
Parameter IndexClassList = "LIS.REST.MSG.PatientReq";

/// 消息签名不能更改
ClassMethod OnBankMsg(pHeader As Ens.Enterprise.MsgBank.MessageHeader, pFullHeaderID As %String, pBody As %RegisteredObject = "", pFullBodyID As %String, pService As Ens.Enterprise.MsgBank.TCPService) As %Status [ Language = objectscript ]
{
		Set tSC = $$$OK
	do
	{
		set clientBodyClassName = pHeader.ClientBodyClassName
		
		/// 如果消息类型在本类的关注列表中,则进行后续处理;否则忽略,只被转储
if ..#IndexClassList[clientBodyClassName
		{
			/// 使用服务实例将Message Bank消息(包含客户端消息信息)传递给后续组件处理
			do pService.SendRequestAsync("MessageBank.Process.ReceiveBankMsgBPL", pHeader)
		}
	} while 0
		
	Quit $$$OK
}

}

注意,尽管整个建立Search Table的过程可以在服务中完成,但由于服务不能开启多进程,对于构建索引这样的高延迟任务,容易变成性能瓶颈。因此,强烈建议将消息转发给BP和BO,并启用多进程处理提高处理速度。

定义好回调函数和Helper类执行,在BS中引用即可,如下: image

在Business Process中分发建立Search Table 建立索引的过程需要应用特定的Search Table类实现,因此通过Business Service将消息分发到Business Process后,则可通过BP根据消息的类型再调用特定的Search Table实现,如下: image

即根据消息类型的不同,使用不同的逻辑进行索引。其中,对于本例的消息类型LIS.REST.MSG.PatientReq image

在switch分支中判定后即可调用对应的代码段处理。 image

在该段代码中,我们需要使用Message Bank消息(该BP的request)中记录的MessageBodyId,对于在源系统中的结构化消息,在Message Bank中被记录为流,该Id即为流记录的Id。根据Id加载流对象后,将该流对象通过IndexDoc方法传递给这类消息对象专用的Search Table实现类完成索引的建立。

Search Table类的实现

该类需要继承Ens.CustomSearchTable并实现OnIndexDoc回调方法,如下:

Class MessageBank.SearchTable.Client.LISReqTable Extends Ens.CustomSearchTable [ Language = objectscript ]
{

///在Search Table中对要建立索引的字段建模,并对该字段建立索引,在查询时即可套用
Property FullName As %String(MAXLEN = 36);

Index IdxFullName On FullName;

///特别提醒,在Message Bank中转储的结构化消息类型会变成字符流,因此,我们是在对字符流建立索引,而不是对源系统的消息类型建立索引
Parameter DOCCLASS = "%Stream.GlobalCharacter";

///建立索引的回调方法
ClassMethod OnIndexDoc(pDocObj As %Persistent, ByRef pSearchTable As MessageBank.SearchTable.Client.LISReqTable) As %Status
{
	set st = $$$OK
	do
	{
		set text = pDocObj.Read($$$MaxLocalLength)
		set text = $ZSTRIP(text, "*C",, $C(9,10,13,133))
///读取字符流建立虚拟文档对象
		set vDoc = ##class(EnsLib.EDI.XML.Document).ImportFromString(text, .st) quit:$$$ISERR(st)
///从虚拟文档对象获得所需的属性值并为Search Table对象赋值
		set pSearchTable.FullName = vDoc.GetValueAt("/PatientReq/FullName")
		
	} while 0
	
	if $$$ISERR(st) $$$LOGWARNING("Failed to index message LIS.REST.MSG.PatientReq:"_pDocObj.%Id()_" "_st)
	
	quit $$$OK
}

}

应当注意的是,使用Search Table支持查询,则意味着查询的目标是Search Table对象而不是直接在Message Bank转储的消息上进行查询。平台的查询功能会负责维护查询逻辑,在Search Table上执行查询并关联到消息上去。 因此,Search Table的属性可以使用消息中的属性组合,大家也可以思考和改进本例实现这样一个场景,源系统中不传FullName全名,代之以分在两个属性中的姓和名。但在Message Bank中却可以在Search Table上建立全名FullName并建立索引,使用户可以通过全名查询消息。

还应当注意到的是,在解析字符流获取所需的属性值时,用户可以选择使用虚拟文档处理,如果能够获得原始消息的类定义,也可以将字符流转换为消息对象再取值。考虑到在实际的生产环境下在Message Bank并不能确保获取源消息定义,采用虚拟文档更为通用且不受类型限制,推荐大家使用。

四. 实现效果

定义好上述代码后启动Message Bank的Production,并测试源系统的接口: image

此时查看Message Bank的production上的消息: image

可看到在Message Bank有新消息触发了处理流程 通过SQL查询Search Table中的记录 image

则可看到最后一行中记录的全名 再转到消息仓库查看器,查询时选择查询表域,选择好对应的SearchTable类型,选择我们刚才使用的全名Biden image

则可查询到消息和对应的Message Trace image

对虚拟文档的处理过程

源系统的消息类型如为虚拟文档,例如EnsLib.EDI.XML.Document,则Message Bank的转储消息类型也是EnsLib.EDI.XML.Document,此时的处理流程与上述流程一致,但处理细节上会简单一些。体现在

MessageBank消息对象的获取

image

如上图所示,不直接使用字符流,通过Id直接获得虚拟文档对象即可。

Search Table的定义

Class MessageBank.SearchTable.DocSearchTable Extends EnsLib.EDI.XML.SearchTable [ Language = objectscript ]
{

XData SearchSpec [ XMLNamespace = "http://www.intersystems.com/EnsSearchTable" ]
{
<Items>
   <Item DocType="example:shiporder" PropName="OrderPerson" PropType="String:CaseSensitive">{orderperson}</Item>
   <Item DocType=":root" PropName="d_e" PropType="String:CaseSensitive">{/root/d/e}</Item>
   <Item DocType=":root" PropName="li_la_c" PropType="String:CaseSensitive">{/root/lis/li}</Item>
</Items>
}

}

如上所示,EnsLib.EDI.XML.Document有系统原生的Search Table模版EnsLib.EDI.XML.SearchTable,继承该类后在XData中定义好Search Table的属性和取值路径(在消息XML中的路径)即可。 关于EnsLib.EDI.XML.Document的Search Table,可通过https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=EEDI_search_tables获取更多信息。

0
0 283
文章 Nicky Zhu · 五月 20, 2021 7m read

一. 企业信息库简介

企业信息库(MessageBank)是一个可选的远程归档设施,可以从多个来自不同实例的互操作性Production中收集信息、事件日志项目和搜索表项。如下图所示: image

这套环境由两种角色的实例构成: 企业信息库服务器,它本身也是一个Production,完全由Message Bank服务组成,接收来自任何数量的客户Production提交的消息、日志等。

客户端Operation(Message Bank Operation),将其添加到一个正在运行的Production中,并用企业信息库服务器的地址进行配置。如连接通畅,消息和日志即可自动转发到Message Bank并在其中存储。

为了使你能方便地看到信息库中的信息,InterSystems IRIS®提供了以下附加选项。

对于企业信息库实例,管理门户自动包括企业监控器页面,在那里你可以监控客户端Production的状态,浏览消息库,并对被监控客户的消息进行检索。

对于每个客户端实例,你在消息库实例中配置一个到企业监控器的链接。

如下所示: image

二. 常见应用场景

消息归档

在使用IRIS互操作性时,对于生产环境,为保障其有充足的磁盘空间和即时查询的效率,通常会采用消息和日志过期策略。在生产环境中只保留近期(如一个月)的信息以备回溯,过期数据将定期被清除。因此,如果有长期保留消息(如在生产环境清除周期之外还需要更长时间的回溯)的需求,则可以通过Message Bank对消息和日志进行长期保存。

企业消息仓库

对于集成规模较大,集成业务较多的大型企业和集团(如大型医院、医联体、医共体),往往会采用多套互操作性实例支撑数据交换和集成业务。在这种环境下,可以通过Message Bank汇聚和存储整个企业环境下的所有互操作消息和日志,为业务集中监控、跨实例业务故障分析等工作创造条件。

消息和日志再利用

理想条件下,实施互操作性项目之后,消息和日志中就会包括大量的业务数据,典型的包括下达的医嘱、患者信息、医疗记录等。通过对Message Bank中的数据进行分析和挖掘,能够获得有价值的业务信息。

接下来我们会为大家介绍Message Bank的搭建过程。

三. 搭建Message Bank

创建Message Bank 命名空间

在生产所用的实例之外,我们需要使用一台独立的实例用于安装和配置Message Bank(实例安装过程和License激活过程从略,请查看安装文档或联系您的支持工程师)。 在该实例上,创建一个命名空间安装Message Bank,如下所示: image

由于Message Bank本质上由Production实现,因此创建命名空间时要选上对互操作Producation的支持。

InterSystems为大家提供了可以套用的Production模版。因此,请按照以下步骤创建Production:

在刚才创建的命名空间MessageStore下创建类MessageBank.BankProduction,继承Ens.Enterprise.MsgBank.Production并将Ens.Enterprise.MsgBank.Production中的XData代码块拷贝到新建的类中,如下所示: image

保存和编译该类,并在Interoperability菜单中加载该Production。 image

其中已部署了两个服务: MsgBankService:该服务通过TCP连接从其他Production接收消息 注意该Service默认使用9192端口与其他客户端通信。 image

MonitorService:该服务收集其他实例的其他Production的运行状态

此时,这个Production已经具备了从其他实例的Production收集消息和事件信息的能力,可直接启动。当然,我们还需要配置与客户端的连接。

为客户端Production添加消息转发Operation

假设我们已经有一个可运行的的如下所示的Production image

注意这个Production与Message Bank不在同一个实例上。 image

这个Production接收XML格式的报文并根据报文类型转发到不同的BO。

要将这个Production加入Message Bank,则需要对该客户端Production添加Business Operation Ens.Enterprise.MsgBankOperation。 image

对于该Operation,需要指定要连接的Message Bank的IP地址和端口。 image

同时,建议开启这个Operation的“启用存档”开关,保证在Message Bank临时故障时挂起消息,在故障恢复后还能捕捉到故障期间的消息和日志。 配置完成后启用该Operation。

在Message Bank中加入客户端信息

上述连接建立后,客户端和Message Bank间的连接已建立,还需要配置Message Bank和客户端Production之间的程序信息(相当于注册)才能正常工作。

添加客户端连接凭据

image

Message Bank需要通过Web请求访问客户端信息,因此,需要配置客户端凭据,即可通过管理门户访问客户端Production的用户名和密码(对访问权限的设计和配置,可参见我们之前的文章:IRIS中的权限管理)

在Message Bank上配置客户端信息

在Message Bank中的Interoperability菜单中找到“企业系统”项 image

在操作页面上通过“新建连接” image

新建连接添加客户端信息。 image

注意其中的服务Web应用路径为该客户端实例上Production所在的命名空间的Web Application根路径,并引用之前填写的凭据。 如配置正确,可通过企业监视器查看连接状态 image

连接成功的状态如下: image

在客户端上添加Message Bank连接信息(可选步骤)

如果需要在客户端上通过链接查看消息仓库的信息,则可以配置链接。 在客户端上,在被采集的Production所在的命名空间的Interoerability菜单中“消息仓库链接”配置 image

输入Message Bank所在的IP、端口和Production所在的命名空间,保存并“开始”即可跳转到Messsage Bank的企业监视器。 image

需要注意的是,该配置固定采用了/csp/[namespace]为Message Bank的Web Application路径,而在Message Bank实例上,这个Web Application默认的路径是/csp/healthshare/messagestorage。可通过在Message Bank上添加一个Web Application,拷贝/csp/healthshare/messagestorage的配置。 image

四. Message Bank的实施效果

测试消息

在客户端的Production中触发任意流程产生消息,如下所示: image

此时通过Message Bank中的“消息仓库查看器”即可查询存储在消息仓库中的消息 image

如下: image

可以注意到该消息已被同步到消息仓库。

需要注意,使用“消息仓库查看器”时,查询的是在Message Bank中存储的消息数据,使用在Message Bank上定义的Search Table或索引进行查询;如果通过“企业消息查看器”查询,则是链接到客户端的消息查看器查询,应用的是在客户端上定义的索引。

消息的存储

根据在源系统的消息类型的不同,传递到Message Bank后会以不同的形式保存消息。

虚拟文档

对于HL7 V2等标准消息或基于XML虚拟文档的消息,在Message Bank这一侧也同样以虚拟文档的形式保存。 image

特别注意其中的如下属性: MessageBodyClassName:该类型为消息在Message Bank侧持久化的类型。 ClientBodyClassName:该类型为消息在客户端侧持久化的类型。 在本例中可以看到,客户端通过EnsLib.EDI.XML.Document类型传递的消息,在Message Bank中也是通过EnsLib.EDI.XML.Document保存。 MessageBodyId:消息在Message Bank中的物理主键 ClientBodyId:客户端侧持久化消息的物理主键 ClientSessionId:客户端会话Id

结构化消息

对于基于Ens.Request等持久化类型的消息,在Message Bank这一侧则默认使用字符流来保存。 例如,对于如下的客户端结构化消息传输 image

在Message Bank中的保存形式为: image

可见: MessageBodyClassName:消息在Message Bank中以%Stream.GlobalCharacter即字符流进行保存

因此,无论是保存为EnsLib.EDI.XML.Document或是%Stream.GlobalCharacter,在Message Bank中保存的消息本身都缺乏足够的结构化特征和索引以支持对消息体的检索,我们会在下一篇教程《互操作消息统一管理系列:SearchTable加速检索》中介绍如何通过构建Search Table来检索这些消息。

对于Message Bank相关的内容,可参见: https://docs.intersystems.com/healthconnect20201/csp/docbook/DocBook.UI.Page.cls?KEY=EGDV_message_bank 也欢迎与我们联系获得更详细的信息。

0
0 363
问题 Michael Lei · 四月 21, 2021

有人有将NonStop SQLMP与IRIS连接的经验吗?

如果可能的话,我需要一些参考或技巧,实际上是与JDBC驱动程序连接的,以便互连并解决许多各种各样的问题,例如:

一些查询(不是很多)有空获取,可以正常工作,但没有要获取的内容,而且确定Select 语句是正确的。

1
0 167
文章 Qiao Peng · 三月 5, 2021 3m read

大家好!

InterSystems IRIS 有一个名为 Interoperability(互操作性)的菜单。

它提供了轻松创建系统集成(适配器、记录映射、BPM、数据转换等)的机制,因此可以轻松连接不同的系统。

数据中继过程中可以包括各种操作,例如:为了连接没有正常连接的系统,可以根据目标系统的规范来接收(或发送)数据。 此外,在发送数据之前,可以从其他系统获取和添加信息。 还可以从数据库(IRIS 等)获取和更新信息。

在本系列文章中,我们将讨论以下主题,同时查看 示例代码 以帮助您了解工作原理以及在系统中集成互操作性时需要进行哪种开发。

首先,我介绍一下我们将在本系列文章中使用的案例研究。

某公司运营着一个购物网站,他们正在更改产品信息的显示顺序以配合季节变化。
但是,有些商品无论季节如何都能卖得很好,而有些商品在意料之外的时间卖出,这不符合当前的显示顺序更改规则,
因此,我们研究了按照当天的温度而不是季节来更改显示顺序的可能性。 调查购买产品时的温度变得非常必要。
由于可以使用外部 Web API 来查询天气信息,因此我们计划收集购买时的天气信息,并将其记录在后面的审核数据库中。

案例非常简单,但您需要使用“外部 Web API”来收集信息,并且需要将获得的信息和购买信息结合起来记录在数据库中。

具体说明将在相关文章中讨论(不包括网站的创建)。 请移步观看!

至于我们这次使用的“外部 Web API”,我们使用的是 OpenWeather当前天气数据.

(如果您想要尝试一下,您需要注册一个帐户并获得 API ID).

以下是一个 REST 客户端发出的 GET 请求的结果(我们将以在 Interoperability 中实现的机制来运行此流程)。

HTTP 响应的 JSON 如下所示:

{
    "coord": {
        "lon": 135.5022,
        "lat": 34.6937
    },
    "weather": [
        {
            "id": 803,
            "main": "Clouds",
            "description": "broken clouds",
            "icon": "04d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 17.05,
        "feels_like": 13.33,
        "temp_min": 16,
        "temp_max": 18,
        "pressure": 1017,
        "humidity": 55
    },
    "visibility": 10000,
    "wind": {
        "speed": 4.63,
        "deg": 70
    },
    "clouds": {
        "all": 75
    },
    "dt": 1611635756,
    "sys": {
        "type": 1,
        "id": 8032,
        "country": "JP",
        "sunrise": 1611612020,
        "sunset": 1611649221
    },
    "timezone": 32400,
    "id": 1853909,
    "name": "Osaka",
    "cod": 200
}

下一篇文章中,我们将讨论如何使用 Interoperability 菜单进行系统集成。

0
0 113
文章 Claire Zheng · 一月 20, 2021 6m read

简介

最近完成了针对IRIS医疗版2020.1版本的性能及可扩展性基准测试,重点关注HL7v2的互操作性。本文介绍了在各种工作负载下观察到的吞吐量,并提供了IRIS医疗版用作HL7v2消息传输互操作性引擎时的系统常规配置和调整准则。

基准测试模拟了与实际环境接近的工作负载(详细信息请参见“工作负载说明和方法”部分)。本次测试的工作负载包括HL7v2患者管理(ADT)和生命体征结果(ORU)数据,并包含数据内容转换和路由。

IRIS医疗版2020.1版本可以表明,采用第二代Intel®Xeon®可扩展处理器和Intel®Optane™SSD DC P4800X系列SSD存储的商用服务器,每天的持续消息吞吐量超过23亿条(入站和出站总量),与此前的Ensemble 2017.1 HL7v2吞吐量基准测试相比,扩展性提高了一倍多。

2
0 348
公告 Claire Zheng · 一月 12, 2021

本报告介绍了ESG 集团对多个数据库管理软件产品进行的并发数据摄取和实时查询性能验证测试。测试结果表明,InterSystems IRIS 数据平台可在摄取上亿条记录的同时执行数百万条查询,响应时间达到微秒级,其性能优于其他传统产品和内存产品。

0
0 142