Orders in different servers

So in the previous post we talked about how we could support the workflow track in the upcoming Connectathon (specifically for diagnostic orders) using a RESTful paradigm. There was quite a flurry of activity on the implementers chat about how this should work – with a number of differing opinions expressed about whether a separate set of resources (the Order / OrderResponse) is required or whether the detail resources (eg DiagnosticOrder, MedicationOrder) are sufficient. This sort of discussion is exactly what Connectathons are intended to promote to that’s all good!

Nevertheless, for this Connectathon we need to proceed with the current arrangement, which will help ‘flesh out’ some of these issues.

In the current version of orders in clinFHIR, all the resources are saved on a single server – which will not be the case in a real world environment. At the very least the clinical record (the EHR equivalent) will be on one server, and the server that processes orders (often called order fulfillment) on another. We’ve talked about Server Roles before and at that time we defined 4 of them:

  • A Patient server that knows about patients (perhaps more generically an identity server because we’d likely want to do the same for Practitioner and other ‘Identification‘ type resources)
  • A data server that represents the clinical record – the EHR/EMR
  • A Conformance server that holds profiling (StructureDefinition) and related resources
  • A Terminology server for expanding ValueSets – and the other Terminology services defined in the spec.

So we now add a 5th:

  • An ‘Order’ server that responds to orders. This might also be called a ‘fulfillment’ server – but we’ll stick with ‘Order server’ for now.

(And just a reminder that a single physical server may implement multiple roles, and that there can be more than server with a given role in any implementation.)

Lets think about what our requirements are going to be from the perspective of the Order Placer for simple order processing in this multi-server world.

  • We want to be able to create an order in our EMR (Electronic Medical Record – Data server) and store a copy of that order in the patient record for reference.
  • We need be able to ‘send’ the order to the Order server so it will be actioned. For example in the case of a blood test this would trigger an entire workflow from the taking of the blood sample all the way through to the creation of the report.
  • We need to be able find out when the order has been completed, and copy the outcomes (eg a DiagnosticReport) into the Local EMR. (An alternative might be to have a ‘distributed record’ where the report remains external to our EMR and just reference it when needed -but even then we’d want to know when it was available).

There are lots of other more detailed requirements – like being able to track the ‘state’ of the referral, be alerted if a report is not done in a reasonable time and so forth, but that will do for now.

Before we go into the details of how this could work in FHIR, we need to review a few important background concepts – especially around identity. We’ve talked about this before, but to re-iterate a few of the important points:

  • Every resource (apart from contained resources) has a unique id – actually a URI – by which it can be referred to. This allows us to build a network of resources to describe clinical (and other) Use Cases. The id must be unique on a given server, and can be expressed either as relative to the server where it is stored (e.g. like /Patient/100) or absolute (eg http:/myServer/FHIR/Patient/100). This difference becomes important when resources are stored on different servers, as we will see.
  • Most resources can also have an identifier. This differs from the id in that the former is a ‘structural’ thing used to locate and link resources, whereas the identifier is a ‘business’ level concept – like a Medical Records Number, Drivers license or Social security number.

Some consequences of this include:

  • A resource representing a single ‘thing’ (like a patient) can potentially be stored on different servers, and so will have a different id on each server, but the identifier (and other properties) will remain the same on each (hopefully!). To know that 2 patient resources actually refer to the same person, you need to look at the identifiers (or other properties) – not the id.
  • If a resource on one server wants to explicitly refer to a resource on another server, it must use an absolute id – the server plus the id on that server. If it doesn’t have that id, then it will need to locate it by using a query (say by identifier), and deal with any duplicates that may occur.

So let’s think about deployment scenarios.

For a start there will be at least an Order server and a Data Server. There might be a separate Patient server as well, but let’s assume that the Data and Patient roles are served by the same server so we can focus on the interaction with the Order server.

For a start, when we create an order, we’ll have a copy on the Data Server (for the patient record) and then make a copy to send to the Order server where it will be actioned by the fulfillment process (whatever that may be). So the order of events will be as follows:

  1. Create the detail resource/s (eg DiagnosticOrder) locally. It will have a relative reference to the patient as it’s on the same server. (Of course, if there were a separate Patient server then it would need to be absolute).
  2. Create and save the Order resource locally. It will have a relative reference both to the Patient and the detail resources.
  3. Save a copy of the detail resource on the Order service by POSTing it to the server. The Order Server will assign a new id, which is returned in the REST response (in the location header).
  4. Make a copy of the order resource on the Data Server. Replace the local relative reference to the detail resource with the one that the order server assigned above, and POST that to the order server. Note that the response from the Order server is the standard HTTP response – not an OrderResponse resource.

(We could have chosen to use the transaction capability and have the server do all the work – but we can’t assume that the Order server will support that).

Job done! – actually no, we need to decide how all of our resources are going to refer to the patient when we send an order to the Order server (as well as the Practitioner and any other referenced resource). There are (of course) at least a couple of options.

  • The order that we sent to the Order Server can have an absolute reference to the patient on the Patient server. This is the simpler option, but assumes a deployment scenario where the Order server is capable of referencing the external Patient server to get the patient details – and most applications will likely want to have a local copy of the patient.
  • We can send a copy of the Patient resource to the Order Server using the conditional create option so it can either create a new Patient resource or find previous one if this is not the first order for that patient. Assuming we take this approach, then there is a step 1a. in the list above where we POST a copy of the Patient resource (after removing the id element) to the Order server with the identifier in the If-None-Exist header. Of course, we’re assuming that the Order server supports conditional create – if not, then we’ll have to:
    • Query for the Patient on the Order server
    • If found, then update the reference in the Order and detail resources before posting.
    • If not found, then POST the new Patient to the Order server, and update the Order & detail reference as above when the Order server responds.

So we’ve sent our order to the Order server. How do we retrieve the result? Let’s assume that we don’t have a notification service (or any other ability to push results) in place – and that we want to continue to use REST – that implies that we need to poll the Order server for OrderResponse resources. However, looking at the OrderResponse resource we see that there is no link to the patient – only to the Order (and the resulting – fulfillment – resources).

We need to query the Order sever for the OrderResponse using the Order Id that was assigned by the Order server when the order was saved, which implies that we need to save that id when the order server saves our order in step 4 above. You might think that adding a Patient reference to OrderResponse will resolve this – but that reference would be to the Order Servers copy of patient, not to our own (unless both were referring to a common Patient server of course).

An alternative way might be to add an identifier to the Order. The Order server will save that identifier in it’s copy, and provided that it supports chained extensions would allow us to make a call like:

/OrderResponse?request.identifier= abc123

Return the OrderResponse resources where the associated order (the request) has an identifier of abc123.

But we probably can’t count on the server supporting that, so the easiest way right now will be to add an extension to our own copy of the order resource which is a reference to the Order Servers copy of the Order. When we want to update our list, we retrieve the extension (which will have the id of the order on the Order server and execute the query:

/OrderResponse?request = abc123

It’s a bit klutzy as we’ll need to update our own copy after it has been saved on the Order server, but it reduces the expectations on the Order server.

Of course, once we have the OrderResponse, if it references any ‘fulfillment’ resources – like a DiagnosticReport – it’s a straightforward matter to copy them to the Data server (though we will need to look for and resolve any relative references to other resources plus copy any dependant resources (like an Observation), so it’s not THAT straightforward…)

 

So we do have a few Requirements of the Order Server:

  • Able to store Order and detail resources
  • Conditional Patient update (to avoid multiple copies of the Patient being created)
  • Perform processing on receipt of the Order resource including:
    • Create OrderResponse resources
    • Create result resources
  • Support the ‘request’ query on OrderResponse
  • Possibly support the chained query for OrderResponse.request.identifier

So this will all work – but the issues we discussed do show that there is room for improvement! If you’re interested in this stuff, then attending the Connectathon will be a great way to contribute to what is likely to be a robust discussion!

 

About David Hay
I'm a Product Strategist at Orion Health, Chair emeritus of HL7 New Zealand and co-Chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the new FHIR standard.

3 Responses to Orders in different servers

  1. Eric Haas says:

    I think that Transactions are the best way. Let the server keep track of the internal references. Imagine a Culture and sensitivity ( Test case order 400 in the Connectathon) They can nest a couple of layers deep. Alternatively as I did for convenience when I created all the resources for the Connectathon, have the client determine the ID using PUTs. Although this may not reflect the real world since you risk collisions if the server isn’t managing the ids.
    Eric

    PS Thanks for this great work.

  2. Sanjeev says:

    Hey ALL

    Can anyone got bench marking information for HAPPI FHIR SERVER. Following are below points.
    1. Whats DB configuration required ( shared memory / data space/ DB execution )
    2. Leucine search index need to keep in disk or any NAS
    3. Whats memory requirement / Machine configuration requirement.( FOR DB/ HAPPI FHIR SERVER INSTALLATION)
    4. For Tomcat deployment can we remove DBCP and use Tomcat connection pool.
    5. Any other performance configuration like thread pool required , as we could find 10 concurrent thread are processing insert statement.

  3. Sanjeev says:

    Hey ALL

    Can anyone got bench marking information for HAPPI FHIR SERVER. Following are below points.
    1. Whats DB configuration required ( shared memory / data space/ DB execution )
    2. Leucine search index need to keep in disk or any NAS
    3. Whats memory requirement / Machine configuration requirement.( FOR DB/ HAPPI FHIR SERVER INSTALLATION)
    4. For Tomcat deployment can we remove DBCP and use Tomcat connection pool.
    5. Any other performance configuration like thread pool required , as we could find 10 concurrent thread are processing insert statement.

    Thanks
    Sanjeev

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: