The Inactivity Timeout is a fixed value, and you can't easily reset it for different times of the day. You can, however, fairly easily control which times of the day alerts are actually sent, based on a variety of criteria:

The TimeIsBetween() and DayIsAWeekDay() functions in the screenshot above are relatively simple custom methods in a class that extends Ens.Rule.FunctionSet, which makes them selectable in the rule editor's function editor dropdown. I wrote them simply for the improved readability they provide for the routing rule.

In the rule above, alerts for the HIE_ADT_out interface are sent only between 7am and 7pm to the Integration team; on weekdays only the help desk is included. Any that fall outside of that timeframe are discarded.

Is that screen shot from the Ensemble Message Viewer? If yes, than what you're seeing is Ensemble's visualization of an empty field/component/subcomponent/repetition. The tilde (~) character is the repetition delimiter at the field level; InterSystems uses the "·" character as an indicator that the repetition was left empty. There's no actual character there to split on, but you can certainly iterate through repetitions within OBX:5 and build a new message segment for each.

The DTL would be something like this:

OK, it's quick and dirty and I'm probably doing something that will make the old-timers here laugh hysterically, but it works. The caveats are:

  • It only cares about word wrapping on the space character. Punctuation adjacent to non-space characters will stay with the adjacent characters.
  • It totally ignores things like \.br\ tags. they're just text as far as it's concerned.
  • It returns a $LIST, where each list element is a line of text from the source string, no longer than the width specified. You can iterate through it with $LISTNEXT or $LISTGET and populate your OBX segments, but you'll probably have to do that in a CODE rule.

So anyway ...

ClassMethod WordWrap(pTxt As %String, pWidth As %Integer) As %List
{
    If $LENGTH(pTxt) > pWidth
    {
        set tLine = ""
        Set tCnt = 0
        Set tWordList = $LFS(pTxt," ")
        Set tListLen  = $LISTLENGTH(tWordList)
        Set tWordPtr = 0
        Set tWordCur = ""
        While $LISTNEXT(tWordList,tWordPtr,tWordCur)
        {
            If $LENGTH(tLine_tWordCur) > pWidth
            {
                Set $LIST(tList,*+1) = $ZSTRIP(tLine,">W")
                Set tLine = tWordCur_" "
                Set tLastCnt = tCnt
            }
            Else
            {
                Set tLine = tLine_tWordCur_" "
            }
            Set tCnt = tCnt + 1
        }
    }
    Else
    {
 	Set tList = $LB(pTxt)
	Set (tLastCnt,tListLen) = 0
    }
    If tLastCnt < tListLen
    {
         Set $LIST(tList,*+1) = $LTS($LIST(tWordList,tLastCnt + 1,tListLen)," ")
    }
    Return tList
}

Have fun!

I'm reasonably confident this will fix the issue without any side effects ...

TIE> Set ^Ens.Queue("ClinicomMsgRouter",0,"count")=0
TIE> Set ^Ens.Queue("PathologyRouter",0,"count")=0
Question though ... do you have the pool size for these routers set higher than 1? I'm concerned about the number of job entries  under each queue. This could have an impact on FIFO, and may have something to do with the erroneous queue counts.

The "N" parameter always creates a new file. If you want to open a file (optionally creating it if it doesn't exist), use "E" instead,  and if you intend to Append to it, include the "A" parameter: open file:("EWA"):1. You don't need the "R" parameter unless you intend to read from it using the same device.

Depending on your Cache configuration, you may not even need the "E" parameter. The default behavior in my Windows installation is to create the file if it doesn't exist, with or without the "E" parameter (the documentation refers to "E" as  "UNIX-only", FYI).

Adding categories will  have no direct impact on message processing. As you noted, there may be a tiny incremental increase in overhead temporarily if you query for them, and you may see a slight delay in the drop-down list ... but only if  you're talking about multiple hundreds of them.

If the intent is to better document your interfaces, though, take a look at the Business Partner configuration. It's an often-overlooked option to keep details regarding the vendor, its contacts, and other information associated with each interface. This may help make the number of categories more manageable.

I haven't had the need to do this yet, but my guess is you're going to have to create a custom operation that modifies the received NAK via the OnReplyDocument() method. If the stack trace is really big, it may be stored as a Stream Object rather than a %String. And if that's the case, you're going to have to scan the Stream for the string you need, and replace the contents of the MSA:3 with that string.

I'd whip up an example for you but I'm headed out the door and will be OoO for the day. I'll check back tonight to see if anyone's beaten me to it :D

Eduard, are you referring to the Priority property of the Ens.MessageHeader class? That seems to be used exclusively for marking the message for Async vs. Synchronous delivery.

The need for message prioritization within a single message flow (one that would otherwise be FIFO) is valid and has been addressed in other integration products. One healthcare use case that I've encountered in multiple implementations is that the downstream system uses a session-oriented connection ("always on" MLLP) and receives both ADT and lab orders over the same connection. As the patient demographic data and "stat" lab orders should always be prioritized over routine order messages, a "high" priority value would be set for those messages during in-engine routing/transformation processing and would be a primary selection criteria for the process (eWay/Connection Point/Communication Client) to deliver it to the receiving system.

Given modern hardware and software, latency caused by the integration engine itself is rarely an issue. However, not all applications can receive messages as fast as integration engines can send them ...

I created a new user with the %Developer role and verified that the class could be debugged successfully. I then added the %SecureBreak role to that user and encountered an issue similar, but not identical to the one reported by @Rueben Van Mol and @Donna.Goodall:

<COMMAND>zDebugStub+30^%Debugger.System.1
Invalid debugger target: ##class(Blue.App.Handler.Absolut).TestConnection()
Target has exited debugger

I've copied your class into my local environment and am not getting any errors using the Studio debugger.

Cache for Windows (x86-64) 2018.1.2 (Build 309U) Mon Mar 4 2019 15:05:44 EST [HealthShare Modules:Core:15.032.9020 + Linkage Engine:15.032.9020]

Class Blue.App.Handler.Absolut Extends %RegisteredObject
{

ClassMethod TestConnection()
{
    w "ok"
    q
}

}


Debugger executing '##class(Blue.App.Handler.Absolut).TestConnection()'
Executing ##class(Blue.App.Handler.Absolut).TestConnection()
ok
Program has terminated.
Target has exited debugger

Scott,

The challenge here is defining what is "long enough enough for a response." One option is to wait forever, but that will have the effect of processing no further messages until the call completes. That can lead to resource contention and race conditions that could be unacceptable in a healthcare setting.

Better to set a timeout and then take some action when the operation fails to complete. Here's a COS example that could be used in a <code> activity in place of a <call>:

set callrequest.ResearchID = context.RschMRN
do process.SendRequestSync("PatientBillingDBPoll", callrequest, .callresponse, 60)
if ('$ISOBJECT(callresponse)) {
   // handle the timeout in here; suspend the message, perhaps?
} else {
   set context.ClarityRs = callresponse
}

This will wait 60 seconds for a response, and if none is received perform the actions in the 'if' consequence.

No, you can't use operands for date math with the "stock" file business service.

I'm assuming that you want to guarantee that only completed txt files are picked up by the business service. In that case, you'll probably want to use the EnsLib.RecordMap.Operation.BatchFileOperation Business Operation class, and update your Record Map to include (and generate) an "empty" batch class.

You can then specify an intermediate file path in the operation's config that will hold the current day's records until the rollover schedule criteria is met. At the scheduled time, the accumulated records in the intermediate file path will be moved to the destination file path and name specified in the config.

Batch class definition:

Sample configuration for EnsLib.RecordMap.Operation.BatchFileOperation, with additional settings required to enable batch rollover:

I actually gave  you half of the answer in my previous comment, but it was easy to miss ... laugh

The Target variable of the DTL will contain the value to which you'll set the callrequest property of the <call> activity:

EDIT: You don't really need to use the request builder for this. Just click on the "+" after Request Actions,  select "set", then select the property and value from their respective drop-down lists.

Yes, it makes sense to set the request class to EnsLib.HL7.Message. However, the response class as Ens.Response is fine since you don't need to create anything to send back to the source business service. Here's a sample Context configuration for the BPL:

To get the segment count for the DG1s, you'd use the GetValueAt() method of the EnsLib.HL7.Message class, and assign it to a context variable. For this you would use the same notation as you would use in the DTL editor to get the segment count:

In COS, a non-zero value is treated as true, so you can use the variable to which you've assigned the count of DG1 segments as the condition for the <if>:

Finally, the context.DG1rec variable from the BPL's Context tab screenshot above was assigned to the record map class used to define the delimited structure. This variable is later used as the Target for the DTL and the value to which the <call> activity's callrequest was set.

I used the same record map class in the Business Operation (BO defined as class type EnsLib.RecordMap.Operation.FileOperation) for the RecordMap field:

This BO will roll over to a new file at midnight each night.

The usual way of accomplishing this is to combine a DTL with a BPL. The BPL is responsible for calling the DTL and sending a record map message for each DG1 segment in the source message.

The DTL rules would look something like this:

The Main BPL structure would first get the number of DG1 segments in the message and <assign> it to a context variable (ex. context.DG1cnt), check to see if any are present, and if yes loop over them. The top-level BPL might resemble this:

The <while> block would create the record using data from the non-repeating portion of the HL7 message and the current DG1 segment, increment the segment counter, and send the record to the outbound operation:

If you haven't worked with BPLs before, you might want to take a look at the self-paced, on-line course.

If you abort all 1040 of them, you're just changing the status to Aborted. They don't "go away," they're just no longer eligible for processing.

If you want to process the first 28 messages:

  1. In the Queue Viewer, select the queued destination from the list
  2. Click "Abort All" in the Queue Contents column
  3. In the Message Viewer, select the appropriate Source and Target Business Hosts, select Oldest First as the Sort Order, select Aborted as Status, and Page Size as 28 (you can enter any value in the page size box)
  4. Click the "Select All" checkbox at the top of the selection column (to the left of the '#' column)
  5. Click Resend on the Message Viewer page
  6. Click Resend from the Resend Messages page