What would be the recommended/best practise approach for the following use case?
Assume the use case where you have a Food Service used to retrieve information about a certain types of food based on a description (for the summary) or an id (for details). The summary and details are provided by third party service providers. The number of 3rd party providers can change in the future for whatever possible reason.
The “search” service has the following schematic representation.
A second service, the “provisioning” service is responsible for calling any third party using an external API. This service has the following schematic representation.
I choose to use two different services for this purpose from scalability point of view and to simplify the possibility to add additional 3rd party providers in the future. Third party requests could be handled by the same instance of the provisioning service or multiple instances of the provisioning service for each 3rd party provider.
The search service maintains a local datastore containing all data that has been retrieved via the provisioning service for future use. Due to usage terms, the cached data needs to be removed every 24h so the local store gets cleaned every cache eviction interval.
Whenever a call to the search service’s REST API is made and no requested data exists in the local cache, a SearchFoodEvent
is sent to the provisioning service to retrieve data from the external source. If data is found, the search service is notified via a FoodsFoundEvent
. The same applies for details about a certain type of food using the RetrieveDetailsEvent
and the corresponding FoodDetailsRetrievedEvent
.
As a side remark, each time the food service stores/remove a type of food in/from its local database, a corresponding domain event (used by services outside this boundary context) is sent.
I have the following remarks/questions about this approach:
-
Are events a suitable mechanism to trigger the corresponding actions in this use case, or are commands better suited?
To my understanding, commands signal an intent to update the state in the domain (maintained by an aggregate). Since the actions in this use case are no changes to the state of an aggregate (there is no aggregate involved at all), commands don’t seem a valid choice. -
The REST API call of the search service might send an event after which it has to wait for the response by the provisioning service. The call should therefore be asynchronous, which is fine, but I would be required to provide some mechanism to wait for the response of the provisioning service to be signalled to the search service.
This seems to introduce avoidable complexities and doesn’t feel right… -
Since the described flow looks like some kind of query behaviour, I wonder if queries could be used instead of relying on events to handle the flow?
Since Axon Framework queries are point-to-point, scatter/gather or subscription based, what would be the best choice? P2P would involve selecting in advance which 3rd provider to use for a certain request since there should only be one query handler in place to handle the query.
What if you would like the case where any response is fine to proceed or what if you would like to use some cascading/fallback mechanism?
The same applies for SG-queries where all query handlers need to respond before you can process their results (at least if I understand correctly). -
Assume you have multiple provisioning services for each individual 3rd party provider. How can you select the appropriate service using the same event definition? A dedicated event property might be a workaround…
I am just wondering what others think a better approach could be assuming you don’t wish to group both the search and provisioning service functionalities in the same µ-svc…
Thank you for your opinion and the time spent to read this (way too long) post