So if your HisEmrRouter is running with 10 jobs, which then sends to ADTRoutingRule that has half the number of jobs available, then I can see that this would introduce some form of a bottleneck.

It's worth considering the impact of increasing your app pool beyond 1 when working with healthcare data, and the details of which are noted here: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls...

It also mentioned not having the poolsize exceed the number of CPU (I assume it means CPU cores) , however this has been contested in the past by other users as seen by the comments of Eduard here: https://community.intersystems.com/post/ensemble-introduction-pool-size-...

If FIFO is not required for your use case, I would at the very least try setting the poolsize to the same value.

Hey Yone.

It doesn't look like There was an ORU^R30 in the standard until HL7 2.5, so that would explain why there isn't a schema.

Depending on your source, you might want to look at how the source system thinks it is providing you a v2.3 ORU^R30 as it's possible they're using the 2.5 schema and then incorrectly calling it 2.3 in the header.

If that is the case, you could create your own schema based off of the 2.5 ORU^R30 to match what you're receiving.

Hey Yone - there's a few things going on here, but I'll try to explain as best I can.

For starters, calling "request.GetValueAt("5:3.2")" is returning to you the value of segment "3.2" of whatever is row 5 of your inbound message. If in your case this is an OBX, then this is only returning the content of OBX:3.2 (Which is some variation of Observation Identifier Text).

When you are then outputting the entire HL7 message to a string and then running "$PIECE(request.OutputToString(), "OBX", 2)" you are getting every character in the string after the literal text "OBX"

So if we use this fake message as an example:

MSH|blahblahblah
PID|blahblahblah
OBR|blahblahblah
NTE|1|blahblahblah
OBX|1|ST|NA^SODIUM^L||139|mmol/L|136-145|N|||F

Calling "request.GetValueAt("5:3.2")" and then evaluating its length would give you 6, as OBX:3.2 is "SODIUM" in the above. If you then output the above into a string and then checked the length of the output from "$PIECE(request.OutputToString(), "OBX", 2)"  you would be evaluating all that is highlighted above.

Now with that being said, it is not a good idea to make assumptions that a specific row within a message will be a set segment type. Certainly in my case, all it would take is for a few NTE segments to be present in a message, and "5:3.2" could easily be part of an OBR or NTE.

Hey Kyle - it looks like I gave you some bad advice. I have just noticed that you're working with a pre-2.4 HL7 schema, and my examples were all based on HL7 2.4 (even where I corrected myself in the second reply). Also in my corrections, I continued to provide examples for a common PID transform, whereas your screenshot shows you doing the transform at the whole message level.

This should work for you:

Sorry about that - hopefully it works for you now smiley

Hey Kyle.

I would approach this by creating a separate count to what is created by the DTL for for each loops, and then iterate through the list of ID's and only move across the ones you want, while not leaving a blank entry in the target message (and remembering to increment the separate count for each ID you copy to the target message).

I have made an example within a common PID transform:

This then gave me:

Hey Oliver.

This Webinar is over on learning.intersystems.com and includes the code sample as an xml that you can import into your environment. The link to the code can be found on this page: https://learning.intersystems.com/course/view.php?id=623 

Make sure you give the code a good read before you try to run it smiley

EDIT: Direct link to the code is here: https://learning.intersystems.com/mod/resource/view.php?id=2388

Hey Yone.

There's two issues with your useage of Ens.Util.Time.

  1. Your spec  in is missing the milliseconds and the timezone offset
  2. You have a % before the T which seperates the date and time

The following should work for you:

Set fecha = "2021-08-18T07:44:14.180+0000"

Set nuevaFecha = ##class(Ens.Util.Time).ConvertDateTime(fecha,"%Y-%m-%dT%H:%M:%S.%N%z","%d/%m/%Y")

Write nuevaFecha

Which should output "18/08/2021"

EDIT: And as Alexander points out - the forth argument outputs the status of your calling of the class, which is very useful for debugging these kinda of issues, but you may want to check for the error in your code just in case the source of the date is formatted incorrectly or some other issue occurs.

Hi Vic.

I hadn't considered that the change in that post would have that effect, as the change was to bring back the ability to set a refresh rate on certain pages - good spot. The Activity Monitor page certainly suggest it should always be refreshing every 60 seconds anyway, so I guess it's another section of the product that had its refresh broken by the changes in 2019... smiley

I was hoping to avoid reinventing the wheel as the dashboard is otherwise functional, but I guess we can't win them all.

I don't suppose you know if 2020 contains any improvement in this area?

Hi Vic.

This is what I expected to work as well, but for some reason the messages don't route if I try this method.

For example this works:

HL7.{PIDgrpgrp(1).ORCgrp(1).OBR:UniversalServiceIdentifier.identifier} contains "ABC"

But this doesn't:

HL7.{PIDgrpgrp(1).ORCgrp().OBR:UniversalServiceIdentifier.identifier} contains "ABC"

Even though I'd expect the "HL7.{PIDgrpgrp(1).ORCgrp().OBR:UniversalServiceIdentifier.identifier}" to return something along the lines of "<ABC><XYZ><LMN>" and therefore would be picked up by the contains function.

Hi Joao.

Here is the working version of the code I referred to - I'm sure someone here can probably look at it and refactor it into 4 lines, but it does the job smiley

 Class DEV.Monitoring.FolderMonitor Extends %SYS.Task.Definition
{ Parameter TaskName = "Folder Queue Monitor"; Property MonitoredFolder As %String; Property AgeToAlert As %Integer(VALUELIST = ",5,10,15,20,25,30,35,40,45,50,55,60") [ InitialExpression = "30" ]; Property SMTPServer As %String; Property SMTPPort As %String [ InitialExpression = "25" ]; Property SMTPUsername As %String; Property SMTPPassword As %String; Property Recipient As %String(MAXLEN = 256); Method OnTask() As %Status
{
Set tsc = ..CheckFileAgeInFolder(..MonitoredFolder,..AgeToAlert,"*.*")
Quit tsc
} Method CheckFileAgeInFolder(Directory As %String, AgeToAlert As %Integer, Extention As %String) As %Status
{
set tSC = $$$OK
// Calculate the file age that we want to trigger the alert // $h is Horolog. HOROLOG contains a character string that consists of two integer values
// separated by a comma. These two integers represent the current local date and time in 
// Caché storage format. These integers are counters, not user-readable dates and times.
// The format is ddddd,sssss //First, take the HOROLOG into a variable so that it isn't different everytime we need to use the HOROLOG.
Set pHorolog = $H //Now break down each part of the Horolog into the days and seconds
set currentdate = $PIECE(pHorolog,",",1)
set currenttime = $PIECE(pHorolog,",",2) // We multiply the AgeToAlert by 60 to convert the AgeToAlert to Seconds so we can use it easily with the HOROLOG.
set pAgeToAlertSeconds = AgeToAlert*60 // At this point, we want to subtract the age to alert from the curent time in seconds. HOWEVER, we can't go negative without going back a day.
// So, to get around this, I have attempted to bodge the checks. If the age to alert in seconds is greater that the 
// current time, we then go back to before midnight... I dunno, I'm just making this up and hoping it works.
If pAgeToAlertSeconds>currenttime {
Set currentdate = currentdate-1
Set timediff = pAgeToAlertSeconds-currenttime
set adjustedtime = 86400-timediff
}
Else{
set adjustedtime = currenttime - pAgeToAlertSeconds
} // We create the value "triggered" with the value of 0 now, so that we can check to see if we need to alert.
set triggered = 0 // We then build a new Horolog by concatinating the currentdate and adjustedtime values
// within the $zdt function. The $zdt function then converts the Horolog to a date/time 
// which can be used for comparing against the datemodified value of the files being checked.
set BeforeThisDate = $zdt(currentdate_","_adjustedtime,3) // Gather the list of files in the specified directory
set rs=##class(%ResultSet).%New("%File:FileSet")
do rs.Execute(Directory,Extention,"DateModified") // Step through the files in DateModified order and compare their date modified 
// with the BeforeThisDate Value to see if any files are old enough to active the trigger while rs.Next() {
set DateModified=rs.Get("DateModified")
if BeforeThisDate]DateModified {
// trigger the trigger
set triggered = 1
} // Stop when we get to files with last modified dates on or after our fileage adjusted date to 
// avoid checking files that don't need to be checked at this time. if DateModified]BeforeThisDate 
set tSC = $$$OK
} // Evaluate if trigger has been triggered if triggered = 1 { //Create and send an email
Set newSMTP=##class(%Net.SMTP).%New()
Set newSMTP.smtpserver=..SMTPServer
Set newSMTP.port=..SMTPPort Set newAuthenticator=##class(%Net.Authenticator).%New()
Set newAuthenticator.UserName=..SMTPUsername
Set newAuthenticator.Password=..SMTPPassword Set newSMTP.authenticator=newAuthenticator Set newEmailMessage=##class(%Net.MailMessage).%New() Set EmailCount = $LENGTH(..Recipient,",")
For i=1:1:EmailCount
{
Do newEmailMessage.To.Insert($PIECE(..Recipient,",",i))
} Set newEmailMessage.From="DoNotReply@imadethisemailupandlackcreativity.co.uk"
Set newEmailMessage.Subject="Queue Building in folder:"_..MonitoredFolder #Dim MessageText
Set MessageText = "<html><head><style>th#la {padding-left: 10px; padding-right:20px; padding-bottom:15px; text-align: left;}td#la {padding-left: 10px; padding-right:20px; padding-bottom:5px; text-align: left;}</style></head><body><table border=""0"" cellpadding=""0"" cellspacing=""0"" height=""100%"" width=""100%"" id=""bodyTable""><tr><td align=""center"" valign=""top""><table border=""0"" cellpadding=""20"" cellspacing=""0"" width=""1000"" id=""emailContainer""><tr><td align=""center"" valign=""top""><table border=""0"" cellpadding=""10"" cellspacing=""0"" width=""100%"" id=""emailHeader""><tr><td bgcolor=""#0072CE"" align=""center"" valign=""top"">" // This is the Header of the email.
Set MessageText = MessageText _ "<h1 style=""color: #ffffff; ; font-size: 28px;"" >Queue Building in folder "_..MonitoredFolder_"</h1>" // This is the HTML for the start of the body which is built up within a table for structure
Set MessageText = MessageText _ "</td></tr></table></td></tr><tr><td align=""center"" valign=""top""><table border=""0"" cellpadding=""20"" cellspacing=""0"" width=""100%"" id=""emailBody""><tr><td align=""left"" valign=""top"">" // This is the Body of the email. These lines can be repeated 
// as many times as needed to act as the lines of text in the email.
Set MessageText = MessageText _ "<p style=""color: #153643; ; font-size: 18px;"">Files are queueing in the folder "_..MonitoredFolder_".</p>" // This line closes off the table secion created above
Set MessageText = MessageText _ "</td></tr></table></td></tr><tr><td align=""center"" valign=""top""><table border=""0"" cellpadding=""10"" cellspacing=""0"" width=""100%"" id=""emailFooter""><tr><td bgcolor=""#0072CE"" align=""center"" valign=""top"">" // This is the Footer of the email
Set MessageText = MessageText _ "<p style=""color: #ffffff; ; font-size: 12px;"">This email was generated automatically by xyz corp.</p>" // This is the end of the HTML.
Set MessageText = MessageText _ "</td></tr></table></td></tr></table></td></tr></table></body></html>" Set newEmailMessage.IsHTML = 1
Do newEmailMessage.TextData.Write(MessageText) ///Send the Email
Set tSC=newSMTP.Send(newEmailMessage)
Quit tSC
}
else{
Quit tSC
}
} }

Hi Joao.

I have a task that runs every x mins to check a folder for files older than y mins, and it then sends an alert to Ens.Alert to then trigger an alert to our team. The logic is, if the file has been sat in the folder for more than the defined period, it is effectively "queued".

However, as I went to dig it out, I have realised I made a mistake with subtracting the seconds from the Horolog near midnight...

I'll try clean it up, and then see if it safe to submit here :)