16

To expand on this existing question Microservices: Worker roles, APIs or both?:

I have seen mixed examples of Microservices implemented as worker roles processing requests off a queue and/or as APIs (REST).

Supporting asynchronous scenarios, a queue can be utilized, with a simple dumb queue listener forwarding the request to a Microservice REST API, where as synchronous scenarios would call the REST API directly.

The term Microservice is vaguely defined I think; do people consider them APIs (e.g. RESTful services) or as any abstract service processing requests, however that request was provided ?

What would we use for naming conventions to differentiate between a service that is running as an API, or a service running as a background worker thread (that pulls from a message queue or runs tasks at intervals)?

This is important to differentiate so that the intent is clear, in that the hosting technologies of web applications allow multiple workers to be span up in parallel, whereas we may want a single worker thread running at any time performing scheduled maintenance tasks.

Further info below.

Scheduled background worker or ServiceProxy

In some cases we may proxy the scheduled background worker to call into the service, i.e:

  1. Run worker
  2. Dequeue while not shutdown
  3. Post into service -> https://myservice.example.com/assets/123?uptime=100&cpu=54

What would we call such a ServiceProxy background worker? I guess if we are worried with concurrency issues and multiple of these background workers running in parallel, then this can be resolved in the call into the service itself.

Client library

I propose a client library to contain:

  1. Methods to call the service to get information
  2. Methods to post to the service (via webservice, transparently handled within the function)
  3. Methods to post to the service (via message bus, transparently handled within the function)

For points 2 and 3 above, there would be no indication other than the function name of the details of how the data is sent i.e. RegisterEndPoint(Guid id, string name) using a standard WebAPI call internally, and SendUpdate(Guid id, HealthPoco stats) using message bus... the client would consume the library without concern for the details.

Project Structure

So far i have as a project structure:

  1. ExampleSolution.Assets.Service - for a WebAPI or gRPC service, multiple of these can run in parallel
  2. ExampleSolution.Assets.ServiceProxy - this is a background worker, generally we want one running
  3. ExampleSolution.Assets.Client - this is the client library that allows communication with the service
  4. ExampleSolution.Assets.Common - related common info such as data contracts
  5. ExampleSolution.EndPoint.CoreAgentApp - endpoint application running on Windows or Linux workstations, there would be other services such as ExampleSolution.Warranty.* etc repeating for Service/Client/Common etc
  6. ExampleSolution.Managagement.Common - common data libaries
  7. ExampleSolution.Managagement.App - functions to call into each individual service to build up the views
  8. ExampleSolution.Managagement.Website - the actual hosted Asp.net MVC application including all web pages, calls the ExampleSolution.Managagement.App functions to retrieve views and perform actions

I would probably put ExampleSolution.Managagement.* and ExampleSolution.EndPoint.CoreAgentApp projects in a separate folder to indicate these are "applications" and seperate away from the "services".

I have seen https://github.com/dotnet-architecture/eShopOnContainers which is clear in how the services are organised, but not clear how scheduled tasks would run:

eshop

And https://learn.microsoft.com/en-us/dotnet/architecture/microservices/architect-microservice-container-applications/communication-in-microservice-architecture

signalr

A project showing both styles of service and SignalR or other message bus service and their project naming conventions would be useful.

I don't want to post off topic or against rules, if anything is vague or intent of the question not clear please let me know and I will expand further.

1 Answer 1

0

I implement four kinds of microservices : repository, view, logic and worker.

Repository microservices

A repository microservice stores one type of elements. Its name is repo-<NAME>-v<VERSION>, for example repo-customer-v1, repo-invoice-v1, ... The API allows to create, update, delete, get by id and query elements. A microservice has a storage and a message queue to notify all the create, update and delete on elements.

View microservices

A view microservice aggregates the content of two repository microservices in order to provides cross searches. Its name is view-<NAME>-v<VERSION>, for example view-customer-invoice-v1, ... The API allows to get by id and query elements. A microservice has a storage and a message queue to notify all the create, update and delete on elements. Creating materialize views is the only solution to provide a search across two repository microservices, because it is strictly forbidden to join the data of two microservices into a database (that would violate the principle of isolation). So if you want to search customers who live in a given town and have invoices of over 100K, you got to create a view microservice that will aggregate the data from the customer microservice and from the invoice microservice.

A view microservice contains a piece of logic that processes the messages emitted by the underlying repository microservices in order to update its internal state. The only way to update a view state is by updating the underlying repositories.

Logic microservices

A logic microservice provides business logic. The API exposes the different endpoints that can be invoked to trigger the processing. Its name is logic-<NAME>-v<VERSION>, for example logic-invoicing-v1, logic-route-computation-v1, ... A logic microservice does not store data. Ideally, it accepts input data, processes them and outputs result data. If necessary, it can query repository microservices to get additional data.

Worker microservices

A worker microservice executes some processing without being invoked (by opposition with the logic microservices. Its name is worker-<NAME>-v<VERSION>, for example worker-endofmonth-invoicing-v1, logic-fidelity-computation-v1, ... A worker microservice can either do its job periodically or when receiving a message. So a worker can process some stuff every hour, or every night, or at the end of each month. Or a worker can process some stuff everytime a message is received from a repository microservice.

By standardizing my microservices, you have the following advantages :

  • you can mutualize a lot of code, specially between repository microservices.
  • you know what each microservice does just by its name. Well, at least for repository and view ones... For logic and worker, you got to come with explicit names :-) But at least you know they are just API or workers !

Note: for the storage, I prefer a no sql database (Cassandra, Elasticsearch, Mongo, ...) over a relational database, it's more convenient to store JSON elements.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.