David Loveluck · Jan 19, 2016 go to post

InterSystems is very committed to this.

We are working through a number of user interface issues in the first design and we are very happy to get suggestions.

David Loveluck · Jan 19, 2016 go to post

Scott

what type of messages are they? I guess since you are using a routing rule they are HL7 v2  or X12 messages, but perhaps not.

If you want to block or route a message based on a field in the message and you are dealing with more than a very small number of customers then I would use a lookup table as you suggest that maps customer identifiers to 0 or 1 so it is easy to reference them in a routing rule.

For a small number of customers that don't change, you could use an In(...) function but I am guessing that is not the case.

David Loveluck · Jan 20, 2016 go to post

Robert

when database encryption was first introduced it was determined that for a particular application that  was very I/O intensive (5,000  block read or writes per second) , encryption would add about 4% to the CPU usage and it can add a tiny amount to disk block latency. 

That is an extreme case, so it is probably an upper bound  for any considerations.

In my experience, very few Ensemble solutions are at all IO intensive, with more time spent on network traffic or CPU usage. So I would be surprised if it is possible to measure the difference in your case.

I don't know about disk encryption.

dave

David Loveluck · Jan 21, 2016 go to post

personally i would use

set mode=$System.Version.SystemMode()

which is documented and therefore a supported API. This package provides a wealth of classes and methods.

Look at documatic for the %SYSTEM package.

David Loveluck · Jan 25, 2016 go to post

Andreas

I don't think there is an easy way to do what you are asking for in a single SQL statement. Mapping Ens.MessageHeader data from different databases into one namespace isn't really possible.

I think you will have to run a query per namespace and merge the results. 

The new activity statistics capability will centralize statistics for many namespaces so you can run a single query, but that isn't available until 2016.1.

Dave

David Loveluck · Feb 11, 2016 go to post

the UI here is not very clear - it suggests that you need an argument, but leaving the box empty should work just fine. No argument will be passed and everything will work fine.

David Loveluck · Feb 11, 2016 go to post

looking at the 2016.2 field test, the red exclamation mark has gone. It normally means the argument is required, so it shouldn't be there, but is doing no harm other than misleading people.

David Loveluck · Feb 26, 2016 go to post

Dan

there are lots of ways of doing this. I find thta building the segment data into strings is often the easiest way to do it because you can see what you have and mistakes are easier to avoid.

The example below builds strings with random data but you could be pulling it form a database. 

If you want to be more sophistcated you could use the SetValueAt() method of an HL7 Segment.

As Stefan says, looking at the generated code for a data transform can often give you good ideas.

Dave

 
//random values. These could be pulled from an application
set PID1=(1+$r(9))_$r(9999999)
set PID2=(1+$r(9))_$r(9999999)
set PID3=(1+$r(9))_$r(9999999)
set PID4=(1+$r(9))_$r(9999999)
set CID=(1+$r(9))_$r(9999999)
set PAC=(1+$r(9))_$r(9999999)
set firstname=##class(%PopulateUtils).FirstName()
set lastname=##class(%PopulateUtils).LastName()
set hl7=##class(EnsLib.HL7.Message).%New()
set hl7.DocType="2.5:ADT_A01"
set tSeg1=##class(EnsLib.HL7.Segment).ImportFromString("MSH|^~\&|HQ|A|||20070222140835||ADT^A01|1"_$r(99999999)_"R"_$R(99999999)_"|D|2.2||||||||||2.2b")
set tSeg2=##class(EnsLib.HL7.Segment).ImportFromString("EVN|A01|200702221400||ADM|MPACPB")
set tSeg3=##class(EnsLib.HL7.Segment).ImportFromString("PID|1|"_PID1_"|"_PID2_"^^^A^MR~"_PID3_"^^^B^PI~"_PID4_"^^^C^PI||"_lastname_"^"_firstname_"||20010101|U||W|122 BIRDSEED ROAD^^SKOKIE^IL^60077^US^^COOK|COOK|(847)676-2211||ENG|S|NON|3000018947054|111-11-1111|||||||||||N||||||||||||||||||||N")
set tSeg4=##class(EnsLib.HL7.Segment).ImportFromString("PD1|||||||O")
set tSeg5=##class(EnsLib.HL7.Segment).ImportFromString("PV1|1|I|E3E^3404^01^E|U|||000764^LERNER^DAVID JOSEPH^^MD^DR|||MED||||R|||000764^LERNER^DAVID JOSEPH^^MD^DR|I|7054|5^20070223|||||||||||||||||||E|||||200702221400|||||||A||000764^LERNER^^^MD^DR")
set tSeg6=##class(EnsLib.HL7.Segment).ImportFromString("PV2||P")
set tSeg7=##class(EnsLib.HL7.Segment).ImportFromString("DG1|1|FF|^OOO^FF||20050101|A|||||||||0||O")
set tSeg8=##class(EnsLib.HL7.Segment).ImportFromString("GT1|1|300001894^^^A^PI|BOOBOO^POOPOO||122 BIRDSEED ROAD^^SKOKIE^IL^60077^US^^COOK|(847)676-2211||20010101|U||P|111-11-1111||||001000^NONE|^^^^^US|||N")
set tSeg9=##class(EnsLib.HL7.Segment).ImportFromString("ZPI|1|N|||||||||20070220|N||^C|001000^NONE|^^^^^US")
set tSeg10=##class(EnsLib.HL7.Segment).ImportFromString("ZPV|1||||||||||N||||O||")
set tSeg11=##class(EnsLib.HL7.Segment).ImportFromString("ZP2|1|x|dgcode|")
set tsc=hl7.SetSegmentAt(tSeg1,1)
set tsc=hl7.InsertSegmentAt(tSeg2,2)
set tsc=hl7.InsertSegmentAt(tSeg3,3)
set tsc=hl7.InsertSegmentAt(tSeg4,4)
set tsc=hl7.InsertSegmentAt(tSeg5,5)
set tsc=hl7.InsertSegmentAt(tSeg6,6)
set tsc=hl7.InsertSegmentAt(tSeg7,7)
set tsc=hl7.InsertSegmentAt(tSeg8,8)
set tsc=hl7.InsertSegmentAt(tSeg9,9)
set tsc=hl7.InsertSegmentAt(tSeg10,10)
set tsc=hl7.InsertSegmentAt(tSeg11,11)

David Loveluck · Feb 29, 2016 go to post

It looks as if  you are receiving a patient query (QRY_A19) so the approach depends on where the information for the reply is going to come from. 

If the BS has all that information in Ensemble then you can just do as you suggest. If it has to come from a downstream system then you might have to use business service setting 'AckMode=Application'. This means the business service will wait for an ACK  to be sent to it from downstream. If that response is exactly what you want, you can use it. Otherwise you will still have to override OnConstructReply to use the ACK to build exactly what you need.

David Loveluck · Mar 3, 2016 go to post

Without a FIFO requirement, you could simpley increase the pool size on the BO; but if you want to maintain FIFO  for messages referring to the same patient, i don't see a simple alternative to your suggestion.

I have seen solutions that put messages for a patient on a hold-queue until they can be processed, but this seems overkill for your situation. It is complicated to get right.

David Loveluck · Mar 14, 2016 go to post

if you are using a routing rule I think you can use the context property Source. So your condition for testing if it came from your "fromLab" busienss service would be 

Source="fromLab"

David Loveluck · Mar 14, 2016 go to post

i thought a routing engine was the harder case :-)

If you are in COS called from BPL then you can access the current BP as 'process' as long as either

a)you do not use the ProcedureBlock class keyword,

or

b) you put process in the public list for you method

then you can access properties of the process such as %PrimaryRequestHeader

ClassMethod MyMethod(vale As %String) As %String [ PublicList = process]

{

   ...

  set src=process.%PrimaryRequestHeader.SourceConfigName

   ...

}

If you are calling a COS funciton from a routing rule, you can get similar information form the variable 'context' which is a reference to an object of type EnsLib.HL7.MsgRouter.RoutingEngine 

David Loveluck · Apr 27, 2016 go to post

Thanks Clayton. 

Overriding OnConstructReply like this is very useful for constructing  non standard ACKs in the HL7 world as well.

David Loveluck · Jun 1, 2016 go to post

Hi James

i don't know exactly what you are doing so i'll give some background and you can ask more questions.

InitStats initializes the local counters. Like resetting and starting the stopwatch.

RecordStats takes the values since InitStats and adds them to the temporary array.

The framework call these two for you. For example Ens.BusinessService.ProcessInput() of a business service calls them to capture the activity of a single invocation of a business service.

If you want to capture stats in your own code you can call them yourself.

If you have called SetStatsUserDimension between the two then that value is put in the userdimension field. For example, if my application has a business service that is accepting orders for widgets then in OnProcessInput I might have the line

     do ##class(Ens.Util.Statistics).SetStatsUserDimension(..%ConfigName,pInput.Color)

and I would be able to get a breakdown of statistics for black, blue or green widgets

If you want to use your own statistics instead of out elapsed time and count, you can use RecordStats to write whatever values you like to the temporary array.

StatsStarted() is supposed to be used to check that statistics gathering has been turned on for the production or config item. For now, just don’t use it and assume the stats are turned on. I will find out more.

I don’t remember what StatsActive() means you probably don’t need to call it. I have never used it.

Dave

David Loveluck · Jun 2, 2016 go to post

I looked at the code and StatsStarted returns 1 if InitStats has been called within the current business service. So it is more than statistics being enabled for that config item.

I will get someone to look at the sample code.

David Loveluck · Jun 22, 2016 go to post

it is intended for constant collection of statistics from a live system.

To minimize the overhead, the counts are accumulated in memory and written to disk at intervals. Benchmarks showed no significant increase in resources consumed with statistic gathering turned on.

This means the package avoids anything that would be relatively expensive to collect. For example several people have asked for the average size of a message to be collected but this would have needed an extra method call to get the information.

It also means that the statistics are not guaranteed to be correct if the system crashes.

David Loveluck · Jun 29, 2016 go to post

you have to be on 2015.1 to have a pure DTL transform of an X12 interchange.

On 2014.1 you will have to use object script to loop over the child documents of the interchange to get the groups and then loop over the child documents of the groups to get the  actual documents. I can't find an example right now, but hopefully another reader can point you to one. 

David Loveluck · Jul 22, 2016 go to post

there is a thread about class queries that gives a full explanation but in this specific case you could do ...

   set statement=##class(%SQL.Statement).%New()
    set status=statement.%PrepareClassQuery("%SYS.GlobalQuery","Size")
   set resultset=statement.%Execute("c:\intersystems\ens20163a\mgr\ensemble","","*")
    while resultset.%Next() {
        write !, resultset.%Get("Name"),", "                                       
        write resultset.%Get("Allocated MB"),", "    
        write resultset.%Get("Used MB")
     }

David Loveluck · Aug 17, 2016 go to post

strictly speaking Ensemble is a separate product. DeepSee is the BI technology that is included in both Cache and Ensemble. Some functionality of DeepSee needs extra license options.

David Loveluck · Apr 28, 2017 go to post

Interestingly, %Net.MailMessage does extend %SerialObject. So you might be able to avoid pulling the email apart and reconstructing it. You could try just creating a persistent message (extending Ens.Request an option but not necessary) with a property of type %Net.MailMessage.

David Loveluck · Nov 14, 2017 go to post

In the video i inadvertently said that the CSP Page statistics were not accessible through SQL. That is not correct. They are accessible through SQL by querying the table %CSP_Util.Performance.

My apologies for the mistake.

David Loveluck · Nov 20, 2017 go to post

It is hard to say, but i think the error is 'Invalid Name' and the reference to locks is just in the text of the long line of code where the error occurs. 

the name it says is invalid appears in the text but it doesn't look like valid COS to me so i can't see how it would compile. i would look at the cached query %sqlcq.DHCdAPP.892.INT and see what code it contains.

David Loveluck · Dec 6, 2017 go to post

If you have a general query this is a great place to ask.

But if you have an operational problem you should pick up the phone (or your preferred technology)  and call InterSystems support. The people there enjoy answering questions and getting systems back in action.

617-621-0700 in the US but if you google InterSystems Support i think you will get what you need worldwide.

David Loveluck · Dec 18, 2017 go to post

I see the images so i don't know what the problem is. I will investigate and fix as soon as i can