Avoiding distributed transactions from UI

29 Views Asked by At

The meat and potatoes of how our website works is that users create an "Activity" when they receive a call from a patient. An activity is essentially documenting what the patient is calling in about and what the ultimate resolution of the problem was. We currently have one service for managing activities, and another for managing patients as we have some integrations with medical records and the like.

One problem that has arisen is that we would like to be able to create a patient on-the-fly when creating an activity if the patient is not already recorded in our system. The problem this creates is that the UI has to POST to the patient service to get back a patient ID for the newly created patient before we can POST the new activity record and save the ID for reference. I am afraid that there is potential for other cases of this as well for entities that live in other services as an activity is where we tend to aggregate references to entities created/managed by other microservices. It is essentially our primary "transactional" service that uses data from the surrounding "supporting" services.

My question is: Is there a general pattern for solving this kind of problem? Does the activity service need to have knowledge of how to create a patient? Is it acceptable to have to make sequential API calls from the UI before creating the activity? Is there some kind of eventual consistency approach that we can despite the fact that we need the UX to be that once they click save the page reloads into a "read" mode with all of the data saved? I don't think the patient and activity services should be merged since patient data is often used outside of the context of creating an activity. Any thoughts?

1

There are 1 best solutions below

0
Julio Di Egidio -- inactive On

Does the activity service need to have knowledge of how to create a patient? Is there a general pattern for solving this kind of problem?

In general, I would have:

  • a "services" layer (e.g. a data access component, a communication services component, access to external identity services, etc.);

  • a "managers" layer (with e.g. patent management vs activity management vs identity management);

  • an "applications" layer (e.g. web site for management operations, apps for field operations, APIs for systems interoperation, etc.)

Moreover, while of course "applications" concretely are deployable components, both my "managers" and my "services" concretely would be libraries (typically, DLLs) with the following discipline:

  • "services" must be independent of each other (cannot reference each other);

  • "managers" may import any needed "services"; "managers" too must be independent of each other (cannot reference each other) -- but on this mileage may vary;

  • "applications" may import any needed "managers"; "applications" too must be independent of each other (cannot talk to each other);

which, overall, entails the existence of some shared abstract types available to be imported in the single components, up to plugin-based and even SDK based extensibility -- but of course I'm rather trying to keep this brief.

Is it acceptable to have to make sequential API calls from the UI before creating the activity? Is there some kind of eventual consistency approach

As illustrated above, I push down that problem to the "managers" layer, anyway it's essentially the same problem: the short answer is "do it in the context of a transaction", but a more technical way to think about it is the Unit of Work.

Indeed, to every possible request/action must (should) correspond a unit of work: where the only real complication is that not all actions are limited to database interactions, in fact there are things that cannot be undone at all, e.g. sending a notification or actioning a robot... and rather domain processes should be designed accordingly!