{"id":14989370,"url":"https://github.com/rithinch/event-driven-microservices-docker-example","last_synced_at":"2025-05-16T12:08:52.787Z","repository":{"id":38394689,"uuid":"171059685","full_name":"rithinch/event-driven-microservices-docker-example","owner":"rithinch","description":"🐳  Simple example of event driven communication between microservices, based on Docker containers, Docker Compose and RabbitMQ. Microservices are implemented in Node.js using Koa.","archived":false,"fork":false,"pushed_at":"2025-02-25T00:51:36.000Z","size":943,"stargazers_count":255,"open_issues_count":68,"forks_count":89,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-09T10:02:03.823Z","etag":null,"topics":["boilerplate","docker","event-driven-microservices","jest-tests","koa","mongodb","nodejs","rabbitmq","rest-api"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rithinch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-16T22:42:58.000Z","updated_at":"2025-03-21T18:25:26.000Z","dependencies_parsed_at":"2024-05-13T20:46:27.032Z","dependency_job_id":"5fe068b5-3cd9-463f-a552-f5c393afe2d7","html_url":"https://github.com/rithinch/event-driven-microservices-docker-example","commit_stats":{"total_commits":89,"total_committers":5,"mean_commits":17.8,"dds":0.4382022471910112,"last_synced_commit":"27d3723acea268f387f019c79f91b685fd1abefc"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rithinch%2Fevent-driven-microservices-docker-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rithinch%2Fevent-driven-microservices-docker-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rithinch%2Fevent-driven-microservices-docker-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rithinch%2Fevent-driven-microservices-docker-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rithinch","download_url":"https://codeload.github.com/rithinch/event-driven-microservices-docker-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254527087,"owners_count":22085918,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boilerplate","docker","event-driven-microservices","jest-tests","koa","mongodb","nodejs","rabbitmq","rest-api"],"created_at":"2024-09-24T14:18:13.637Z","updated_at":"2025-05-16T12:08:52.713Z","avatar_url":"https://github.com/rithinch.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Event-Driven Microservices Backend Sample\n\nProof of Concept for a scalable Local News Application, based on simplified event-driven microservices architecture and Docker containers. :whale:\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=rithinch_event-driven-microservices-docker-example\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=rithinch_event-driven-microservices-docker-example)\n[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)\n[![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/rithinch) \n[![HitCount](http://hits.dwyl.io/rithinch/Event-Driven-Microservices-Sample.svg)](http://hits.dwyl.io/rithinch/Event-Driven-Microservices-Sample)\n\n[![forthebadge](https://forthebadge.com/images/badges/made-with-javascript.svg)](https://forthebadge.com)\n[![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com)\n\n## Introduction\n\nThis repo presents a proof of concept of a highly scalable local news application backend. The application was developed keeping a local news domain in mind, but the principles used can easily be applied to design software solutions for any domain. One of the primary business requirements for a local news application domain is that it has to be blazing fast since news updates are requested very often by customers and it would largely benefit the business if the system architecture can support such scale. After evaluating several different system architectures, a hybrid event-based microservices architecture was designed to meet the requirements. This approach leverages RabbitMQ message broker for events communication between the microservices and all the services are containerized using Docker such that they can independently developed, deployed, monitored and scaled.\n\n## Full Application Backend Demo\n\n[![Video](https://img.youtube.com/vi/F2uVu6hKZTc/0.jpg)](https://www.youtube.com/watch?v=F2uVu6hKZTc)\n\nThe following video demo shows all the currently supported features for the proof of concept. It goes through how to run the application stack and perform operations requesting the api's.\n\nEvent-based communication samples are highlighted in following two scenario's:\n* When a new article is added through articles-management service, the notification service picks up that event and sends an email to the admin with the article details.\n* When a new user is added through user-management service, the authentication service picks up that event and stores the login details of the user. Demonstrating Atomic Transactions in a Microservices Architecture. \n\n## Running the entire application stack\n\nIf you have docker-compose installed and docker running; it is really simple to spin up the entire application stack.\n\nMake sure you are in the root directory of the repository where the docker-compose file is.\n\n**docker-compose up** starts it and **docker-compose down** stops it\n\nExample:\n\n```\ndocker-compose build --no-cache\ndocker-compose up\ndocker-compose down\n```\n\nAll the environment variables for the application need to be specified in the docker compose file, each service has environment/config.js which can used in anywhere in it's service application to get the config files for that instance. This allows to seperate environment configurations concerns from our applicaiton code meaning it can easily spun up for local, development and production environments with different db credentials, ports etc.\n\n## Working Features\n\nOnce you run the entire application stack using docker compose, you should be able access the public routes below:\n\nFeature | Type | Route | Access\n------------ | ------------- | ------------- | -------------\nGet all articles | GET | http://localhost:3000/api/articles | Public\nGet a specific article | GET | http://localhost:3000/api/articles/:id | Public\nAdd a new article | POST | http://localhost:3000/api/articles | Protected\nUpdate an article | PUT | http://localhost:3000/api/articles/:id | Protected\nDelete an article | DELETE | http://localhost:3000/api/articles/:id | Protected\nGet all events | GET | http://localhost:3001/api/events | Public\nGet a specific event | GET | http://localhost:3001/api/events/:id | Public\nAdd a new event| POST | http://localhost:3001/api/events | Protected\nUpdate an event | PUT | http://localhost:3001/api/events/:id | Protected\nDelete an event | DELETE | http://localhost:3001/api/events/:id | Protected\nGet all users | GET | http://localhost:3002/api/users | Public\nGet a specific user | GET | http://localhost:3002/api/users/:id | Public\nAdd a new user | POST | http://localhost:3002/api/users | Protected\nUpdate an user | PUT | http://localhost:3002/api/users/:id | Protected\nDelete an user | DELETE | http://localhost:3002/api/users/:id | Protected\nAuthenticate a user | POST | http://localhost:3003/api/auth | Public\n\nFor protected routes: you can post to http://localhost:3003/api/auth first with the following 'body' to get the admin token\n\n```json\n{\n\t\"emailAddress\": \"rithinch@gmail.com\",\n\t\"password\": \"Testing0*\"\n}\n```\n\nThen put the recieved token in the authorization header for other protected routes.\n\nOfcourse, now with that in place you can create new users and authenticate with their credentials next time to get a different token. :grimacing:\n\nTo add a new user send a post request to http://localhost:3002/api/users with the following json body structure and its contents:\n\n```json\n{\n\t\"firstName\": \"New\",\n\t\"lastName\": \"User\",\n\t\"emailAddress\": \"newuser@new.com\",\n\t\"description\": \"New User\",\n\t\"password\": \"Testing0*\"\n}\n```\n\n## Event-Based Communication Between the Microservices - Example\n\nThis is where things get interesting, our microservice ecosystem consists of 5 microservices. 4 of them are public facing exposed via an api i.e articles-management, events-management, users-management and authentication. We also have an internal notification microservice (no client apps have access to this). These 5 services form our application microservice ecosystem.\n\nNone of the microservices talk to each other directly (using their api's) ... wait.. what.. then how is notification service sending an email when article-management service adds an article? :confused:\n\nUsing a Pub/Sub pattern with RabbitMQ message broker. Which means that mean a client sends a post request to article-management service; the service processes the request and after it's done, it simply publishes a message with some payload to 'article.added' exchange and completes the request.\n\nNow within our ecosystem if any microservice is subscribed to that event it will be alerted and start to process the recieved message with payload. So in this case, our notification service is subscribed to the article.added' exchange. \n\nThis also means that we can have multiple subscribers to that event, so article-management doesn't need to worry about who is subsrcibed it can simply publish the message finish the request. This makes our services loosely coupled and we can easily add more independent services to our ecosystem.\n\nAll our services are can be run, developed and scaled independently. :sunglasses:\n\n### Code example:\n\n**Publisher**:\n\nIf you see the file 'article.added.js' in services/articles-management/src/message-bus/send folder; that is being used in add method of controllers/article.controller.js and is called when the adding finishes.\n\n**Subscriber**:\n\nIf you see the file 'article.added.js' in services/notification/src/subscriptions folder; that is called in the server.js of the file, so telling the node application to start listening to that service.\n\nAnother such event based communication is applied in this demo; when adding the user through user-management service. The responsibility of user-management service is to handle adding of users and user releated activity on the application (their likes, bookmarks) etc. The responsibility of the authentication service is to handle authentication related activites i.e assigning token if the password is valid, password reset routines etc. But users can be created only through user-management service... then how is that user record created in the authentication db? \n\nSimple.\n.\n.\n**Events**. \n\nThis allows us to handle inserting of data in two microservices from one request. Atomic Transactions are crutial for complex business domain and can be challenging when dealt within a microservices architecture. Event Sourcing patterns play a large part in microservice architecture design patterns. \n\n**Microservices + Events + Docker = Awesome DevOps** :bowtie:\n\nUnderstanding the above concepts are the just foundations to get started with the modern trio (Microservices+Events+Docker), there is still a lot more to learn and explore when adapting such an architecture in an production environment. Especially handling issues disaster recovery challenges and monitoring.\n\nI found the book, [Microservices Architecture from O'Reilly](https://www.oreilly.com/library/view/microservice-architecture/9781491956328/) a good read for learning about microservices concepts and how to approach about building such systems.\n\n## Running the Unit Tests\n\nGo to the respective service directory where the package.json is and run tests.\n\nEg: to run the tests for the articles-management service\n\n```\ncd services/articles-management\nnpm test\n```\n\nTo run all the tests for all microservices, a script 'run_all_tests' has been created in the root directory.\n\n```\n./run_all_tests\n```\n\n## Running the linter\n\nGo to the respective service directory where the package.json is and run linter.\n\nEg: to run the tests for the articles-management service\n\n```\ncd services/articles-management\nnpm run lint\n```\n\nAll services have adopted the eslint airbnb configuration. A strict linting policy has been followed to ensure consistent code is produced.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frithinch%2Fevent-driven-microservices-docker-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frithinch%2Fevent-driven-microservices-docker-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frithinch%2Fevent-driven-microservices-docker-example/lists"}