Scaling Patient Flags 2.x module GSoC 2023 project: Moving forward with patient Flags in RefApp 3.x

Problem

The RefApp 2.x openmrs-module-patient-flags module is not worthy of integrating into OMRS 3.x.
This is ideally because the Uganda EMR team reported that the RefApp 2.x version of this module is slow. This is because the patient-flags-module defines a mechanism which evaluates flags live. When a patient is brought up, the system runs scripts against the patient’s data to determine the flags. However, this system may not be scalable as it may be too slow to display more than one or two flags.

Solution

The FHIR Flag resource can be used to store data related to flags. The data stored should include, at least, the data in the FHIR flag model. This would allow us to build out how patient flags are created in different mechanisms. The patient flags are already created as part of the CDS scripts in SQL, so importing those flags is ideal. The flag module should store only unexpired flags.

I proposed this as a project for GSOC 2023 so that a GSOC student can update this module.

REF:

https://wiki.openmrs.org/pages/viewpage.action?pageId=302514286

cc @dkayiwa @ibacher @grace @suruchi

2 Likes

Wow, this is a good project, I would love to work on this project alongside anyone contributing to it. A IDI and soldev Team, We envision enhancing patient flags in call for life systems across different implementations in Africa, However, we realized that capturing flags using FlagEndpoints, It was not something the community embraced. Being that, we can discuss further how we can achieve this. cc @pwargulak

I

1 Like

Thanks @sharif for the mention.

It’s an interesting project. In Connect for Life, we are using patient flags in one of the implementations, in productive environment and we did notice the performance issues @jnsereko mentions - we have flag which takes couple of seconds to calculate.

2 Likes

@jnsereko how about evaluating these flags in some sort of background daemon thread and storing the precomputed results. That way, the patient dashboard loads the already stored computed results. We would then need to keep it in sync with the obs or any other data which could potentially affect the computed results. To give an example, we could for instance spawn a background thread to recompute for a patient (or a group of patients depending on the type of flags), on form submission. Or simply do this as AOP around the ObsService or any other relevant services, for data submitted outside of forms. This can be refined further, but just wanted to start by throwing in some rough ideas on the possible next steps.

1 Like

Thanks @dkayiwa. I would personally go with option 1, spawn a background thread to recompute...

I think we shall need to;

  • Enable asynchronous processing in the 2.x patient flags module
  • Modify the existing a service class that handles flag evaluation by adding an asynchronous function that accepts a patient or group of patient as parameters and paste Flag revaluation logic there.
  • In the controllers, we shall just call that asynchronous function and pass the desired patient or group of patients.

cc @ibacher

Hello @jnsereko ,

I see that this idea was not implemented for GSOC '23 but I can also see that it is a pending project idea for GSOC '24. Given that it is used across implementations and the performance issues reported by the community, repurposing the patient flags module would make for a great GSOC project this year.

I have read some past discussions on the issue(and still reading to find out more) and I would like to work on it. Any light you shed on the subject will be greatly helpful.

@dkayiwa

@wikumc is setting up the project page.

I created the project page: Validating and re-working (updating) the OpenMRS PatientFlags module - Resources - OpenMRS Wiki

4 Likes

Would this period be a good time to also add functionality so that patient flags can easily be translated back and forth between the Flag - FHIR v5.0.0 Resource and the OMRS Flag model?

I don’t think this should be so hard, never the less, we can mark this project advanced in case the logic looks a bit complicated.

1 Like

To add onto this important comment, this comment by you :slight_smile:

I love this idea. @wikumc what do you think?

I think it is a great idea. I’ll add this to the project objectives list.

Hello @jnsereko

I still have some issues I have failed to understand and I kindly ask that you explain a little bit more. How exactly would storing the flag data in the FHIR Flag resource(as opposed to how it is done currently) help improve performance of the module? And also when you say this would allow us build out how patient flags are created in different mechanisms, do you mean in the context of Groovy flags/SQL flags/logic flags or something else?

If you have any other ideas regarding the problem and its approach, I would be grateful if you shared them, since I am trying to gain a better understanding of the problem at hand. Thanks.

cc: @wikumc

@jnsereko are we going to use FHIR API instead using OpenMRS flag API ?

We are actually going to use both. A possible scenario would be that a GET / POST from the frontend should point to openmrs/ws/fhir2/R4/Flag... where the OpenMRS FHIR2 module will translate these parameterised flags properties into OpenMRS Flags Model and vice versa. Sample code show a picture of how the translation will be done.

	/**
	 * Maps a {@link FhirFlag} to a {@link Flag}
	 * 
	 * @param openmrsFlag the OpenMRS Flag to translate
	 * @return the corresponding FHIR Flag
	 */
	Flag toFhirResource(@Nonnull org.openmrs.module.fhir2.model.FhirFlag openmrsFlag);
	
	/**
	 * Maps a {@link Flag} to a {@link FhirFlag}
	 * 
	 * @param fhirFlag the FHIR Flag to map
	 * @return the corresponding OpenMRS Flag
	 */
	FhirFlag toOpenmrsType(@Nonnull org.hl7.fhir.r4.model.Flag fhirFlag);

cc @tjnangosha

1 Like

I have some confusion regarding how the flag evaluators operate. From my current understanding, there are four types of evaluators. Could you please explain how these evaluators work?

Additionally, what is the purpose of the PatientFlagTask?

CC : @wikumc @dkayiwa

@manojll A flag is essentially a message tied to specific criteria. If a patient’s details match with the specified criteria module will display the corresponding message on the patient’s profile. Users could write these criteria using different languages and evaluators are used to check whether the patients’s condition matches these criteria. There are 4 types of evaluators.

  1. SQL flags: Conditions for the flags are written in SQL.
  2. Groovy flags: Conditions for the flags are written in Groovy
  3. Custom flags: Conditions are checked using a custom evaluator.
  4. CQL flags: Conditions are checked using CQL (currently not in use)

You could try creating these flags from here: http://localhost:8080/openmrs/module/patientflags/editFlag.form

The PatientFlagTask class is responsible for asynchronously generating and evaluating flags.

2 Likes