Announcement

Collapse
No announcement yet.

Filter SMTP Destination - Unique only

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Filter SMTP Destination - Unique only

    What I have set up is a channel that watches SIU messages and if the appointment date is within the next 3 days (and meets some other criteria) the message is forwarded to the destination filter which sends a templated email that contains some basic patient and appointment information.

    The challenge is that any time someone touches the appointment it creates a new HL7 message sometimes over 30+ in one day. I am trying to conceptualize a way to prevent the duplication of messages being sent on the same day and was hoping someone could assist me.

    The templated message sends the patient first/last name, MRN, Provider, Activity type and Appointment Date/Time. Ideally, I would like the ability to instruct:

    If this exact (email)message has already been sent today, don't send it again.

    The trouble I run into is where will I get that comparison information? Is there a way I can reference the outgoing messages from the channel message section? Or would I need to somehow pass all the filtered messages into an array, after the source filter, before the destination filter, and then use the array for the source of comparable information?

    For reference this is an example of the templated message that is sent out with the velocity variables:

    Please see the details below for an upcoming appointment that is scheduled to occur within the next three business days.

    Patient Name: ${patient_first_name} ${patient_last_name}
    MRN: ${mrn}
    Provider: ${provider_first_name} ${provider_last_name}
    Activity Type: ${activity_type}
    Appt Date/Time: ${appt_date_time}

  • #2
    any time someone touches the appointment it creates a new HL7 message
    I'd bet those are S14 (appointment modification) trigger events. Sounds like you may just want to monitor/filter for S12 (appointment booking) trigger events. The trigger event type is in MSH-9.2
    Last edited by jkrebs; 05-06-2020, 04:58 PM.

    Comment


    • #3
      Originally posted by jkrebs View Post
      Code:
      any time someone touches the appointment it creates a new HL7 message
      I'd bet those are S14 (appointment modification) trigger events. Sounds like you may just want to monitor/filter for S12 (appointment booking) trigger events. The trigger event type is in MSH-9.2
      *facepalm* Yes! This is exactly what I need. Thank you!

      Comment


      • #4
        Thanks for the feedback! Good luck with the project!

        Comment


        • #5
          Originally posted by jkrebs View Post
          Thanks for the feedback! Good luck with the project!
          So that did reduce the number of duplications by a lot; sometimes we would see over 100 and now it's more like 1 - 5 per appointment. I would still like to refine it further. Is there an easy way to reference the sent messages that are stored in mirth as a filter variable? The only other thing I'm thinking otherwise would be to feed the outgoing messages into a DB or an array of some kind and create logic to check against that? Anyone else have any concept on how I might accomplish this?

          EDIT: So I have discovered a section of the message that is unique SCH.1.1 What I would like to do is to create a destination filter that states if SCH.1.1 is unique then transform/send the message via the destination channel. A second edit rule that states if SCH.1.1 is not unique and (list of velocity variables) are the same then filter the message. I feel this would accomplish what I want. My challenge is how to reference messages that have already been sent. The channel messages contain everything I want to compare against but I can't find an easy way to reference it.

          Am I correct that I should be feeding the veloctiy variable data into a DB and then create a call to the database that would perform the logic for the edit rules to return true/false. Obviously I would have to build in some retention rules and such to ensure the DB doesn't get too big but I wanted to try and get the concept right first and figure the details later.
          Last edited by pmurraygic; 05-20-2020, 10:57 AM. Reason: Further explain...

          Comment


          • #6
            Don't know if you can access the message store directly or not. Have just assumed your second option was the only option. I've done similar using a text file w/another (very limited) engine where I created a vbs to allow users to regularly update a file and then checked against the file with the engine to filter messages. Writing the messages (maybe just the message date/time or the unique vars you've identified) to a file and then filtering w/another channel or destination might be an option.

            Worth investigating if the original message can be accessed but I don't have a specific answer at the moment.
            Last edited by jkrebs; 05-20-2020, 11:21 AM.

            Comment


            • #7
              You would have to perform a search in a similar manner to how the message browser works in order to pull old messages and then parse out the correct content. It would be pretty hacky and slow.

              You could certainly use a database to store your unique values, but a simpler solution could be to use a data structure kept in the globalChannelMap.

              Pros would be easier to implement and faster lookups than db. Cons would be that if your mirth service restarted, you would lose your history. This might lead to duplicates until the cache rebuilds (no more than 1 dup per unique value.)

              Mirth ships with the Google Guava library, which has a nice tool for building simple in-memory caches.

              For example, in your channel deploy script:
              Code:
              with (JavaImporter(
                      com.google.common.cache.CacheBuilder,
                      java.util.concurrent.TimeUnit
              )) {
                  // cache can be set to expire entries after last access or after last write
                  var cache = CacheBuilder.newBuilder().expireAfterAccess(2, TimeUnit.DAYS).build();
                  // get cache as a java.util.concurrent.ConcurrentMap
                  var map = cache.asMap();
                  $gc('cache', map);
              }
              Then in your filter:
              Code:
              var uniqueValue = msg.SCH['SCH.1']['SCH.1.1'].toString();
              // The value we are storing doesn't really matter, so make it the same as the key
              var result = $gc('cache').putIfAbsent(uniqueValue, uniqueValue);
              // if result is null, then uniqueValue was not in the cache
              return result == null;

              Comment


              • #8
                Originally posted by agermano View Post
                You would have to perform a search in a similar manner to how the message browser works in order to pull old messages and then parse out the correct content. It would be pretty hacky and slow.

                You could certainly use a database to store your unique values, but a simpler solution could be to use a data structure kept in the globalChannelMap.

                Pros would be easier to implement and faster lookups than db. Cons would be that if your mirth service restarted, you would lose your history. This might lead to duplicates until the cache rebuilds (no more than 1 dup per unique value.)

                Mirth ships with the Google Guava library, which has a nice tool for building simple in-memory caches.
                I had just finished setting up MySQL Workbench and was heading down the DB route but this seems much more straight forward. I will have some follow up questions though. First I would like to start with the deploy channel script. When the code says:

                Code:
                // cache can be set to expire entries after last access or after last write
                var cache = CacheBuilder.newBuilder().expireAfterAccess(2, TimeUnit.DAYS).build();
                Am I understanding correctly that if it's read by the filter rule the cached message will then expire (be deleted) OR it will expire after 2 days? So in a situation where five messages with the same SCH.1.1 data are transmitted there would never be more than one in the cache and all would be gone after 2 days?

                Should this code go in the postprocessor script to avoid it comparing to itself?
                Last edited by pmurraygic; 05-21-2020, 10:13 AM.

                Comment


                • #9
                  expireAfterAccess means that a key will remain in the queue for the specified amount of time (2 days in my example, but it can be anything you want) since it was last written to or checked. In practice this would mean if you haven't received a certain SCH-1.1 value in more than 2 days, the cache would forget about it, and if it were to come through again it would be treated as new.

                  I specified where each block of code should go. The block in the deploy script creates the cache when the channel is deployed and stored it in the globalChannelMap. The fliter block accesses the (one and only) cache from the globalChannelMap.

                  When the filter calls putIfAbsent, it adds the unique value as the map key to the cache if it didn't previously exist, and then returns the old map value. If the key did not previously exist, it will return null, and then we know this message needs to pass the filter. If it returns a non-null value (because we're setting it to be the same as the key, which isn't null) then this is a duplicate, and the message is filtered. The cache expiry timer for this key is also reset at this point since it has been accessed.

                  Comment


                  • #10
                    I really appreciate you taking the time to answer my questions. Further understanding helps me to be able to build on it. Trying to avoid just copying and pasting code. I am going to try and at some additional logic and post if (when ) I run into additional challenges.

                    Thank you!

                    Comment

                    Working...
                    X