Microservice architecture is growing in popularity. In this article, we will take a look at what’s happening under the hood of a project Scandiweb is working on— what microservices are used and what are their functionalities! But before we get to that let us take a quick look at its infrastructure.
Why a Microservices Architecture?
With microservices there are both benefits and downsides, so we had to evaluate if they are right for us. The most important consideration was that given the large scale of the application, we needed the possibility to split all functionality into small chunks and easily disable or enable specific functionality based on different variables.
We knew that we will be working with multiple applications and quite a big team. Microservice architecture allows us to assign developers to work completely independently on separated parts of functionality without crosspasing other developers.
The main thing that should be noted is that we use a similar infrastructure for most of our projects. Why? Because it works perfectly. If you are interested in the infrastructure aspect — which AWS services we are using and how we manage them with Terraform — take a look here at Publica’s example. The infrastructure for the two projects is almost identical. The most considerable difference is that the current project uses GraphQL to interact with APIs across all microservices. If you have any questions that remain unanswered by this article — ask us directly!
That being said, it’s time to take a look at the various microservices we use!
Packages, Tools, and Microservices
We try to split our functionalities into microservices as much as possible. When we feel like an MS starts doing something it shouldn’t, it’s time to separate the functionality and create a new MS. Besides working through GraphQL, almost every microservice provides a private API layer which we are using in our Admin Dashboard. Recently, we updated our GraphQL setup and made it work with WebSockets.
This is a very exciting feature that allows us to use Subscriptions and update data in our application in real-time. This is especially helpful for things like Leaderboard which are constantly changing, as well as for tracking network/referral updates.
Gateway is the entry point for all our GraphQL requests. All of our requests are protected by JSON Web Token (JWT) and the user won’t be able to make any request unless the proper header is provided. It is the only external instance that has access to internal microservices. Gateway combines all the remote schemas from each microservice and builds up its documentation from there.
Users is a microservice responsible for storing basic user data (first name, last name, e-mail, etc) and providing CRUD requests for most of that information. It also includes functionalities for registration, login, password retrieval.
Network is the second main microservice and it builds our binary network tree. It is responsible for creating nodes, assigning seats to each node, degradation logic, various overall interactions with a tree. It is heavily covered with unit/integration tests because it is a crucial part of our application and we cannot afford to make mistakes there.
Challenges is the first part of the gamification process in the application. It allows us to build user missions (quests) that can be completed and the user can be rewarded for doing so. Everybody likes free stuff and this mission will keep a user motivated to keep opening our application and kindle repeat interest.
All challenges can have multiple sub-challenges. For example, the first challenge that any user will get is to complete his or her profile information to “Become a Member”. To complete this challenge, the user will need to fill in personal details, upload an avatar and turn on push notifications.
The rewards can be monetary or benefit the user in other ways, as is in the case of “Become a Member” challenge, where you are rewarded with unlocking the leaderboard.
Leaderboard is the second part of gamification. There are two types of leaderboards — weekly and all-time. The initial plan was to make rankings based on the number of referrals a user has invited, with more referrals equaling a higher rank.
But, after a brainstorm session, another idea came up and it was to make it based on points, with various actions in the application giving the user different amounts of points. The ranks are calculated by simply adding up the points. Each week, the 3 top users will receive prizes — those can be monetary or something like gift cards. At the end of the year, the top-ranked user will get a car.
Cron is pretty self-explanatory. It schedules various tasks like weekly leaderboard reset, push-notification sending before the leaderboard reset, updates expired seats in the network, etc.
Mail is straight-forward as well. It sends various e-mails like a welcome e-mail after registration, new referral registration, educational e-mails, etc.
Notifications is responsible for sending various push-notifications. It can be either general notifications with custom text or event-based ones, like the mentioned leaderboard reset, referral registration, etc.
Transactions is a microservice that manipulates user balances. Every action that somehow affects user balance will go through this service. Winning of the weekly leaderboard, challenge completion, referral registration, all of those actions will deposit money to user accounts and, of course, the bonus system itself will also work closely with transactions.
This is another important part of our ecosystem. Basically, there are two ways a user can get cash bonuses — Card Link Offer (CLO) or Gift Cards. We need to store information about all the merchants and their offers that are available to the user, and we need to have the ability to manipulate those offers. For example, if one merchant offers a $10 bonus on Nike and other one offers $15 we want to make sure the user sees the best offer. This service is responsible for that and it works closely with aggregators.
Gift Card Aggregator
As mentioned before, there are many merchants and interactions with them happen through their 3rd party API. Therefore we needed to develop an aggregator (middleware) that will talk with all of those API’s, collect all the information regarding offers, provide conflict resolution for the admin (because one merchant can have Nike under the “Nike” title and the second one might have it under “Nike US”) and provide all that information in the same predefined format to the Merchants microservices for storage.
Card Link Offer Aggregator
It’s pretty much the same service as a Gift Card Aggregator, but instead of Gift Cards it works the same way with Card Link Offers.
Secure Storage (Gift-Cards)
For the gift-cards we need to have an additional security level — we don’t want to show users gift-card information before the actual purchase process. That can be abused in various ways. Therefore, we needed to develop secure storage that will encrypt all the information regarding the gift card. On the front-end level, the user won’t even understand that he’s paying with the gift-card until the very end of the transactional phase.
Admin gateway serves the same purpose as a regular gateway, but instead of working with user accounts it will work with admin accounts and the admin panel, it has its own requests that are aimed at various types of data manipulation.
We obviously wouldn’t want to configure everything every time we start a new microservice and so we created Boilerplate with all required base setups, so new set-ups are quick and efficient!
Models is our small package that holds all the general type definitions of the GraphQL data. Look at it as a JSON formatted description of all the “types” and their fields, for example “User type” has “id” field which is a “Int”, “First name” field which is a String and so on. This package is required to keep definitions DRY and reuse them across all of our MSes.
Logger is another small package that has our own configuration for the Winston logger that is reusable across all microservices. It outputs log information in a console in a friendly format and it saves critical information in log files, which we retrieve later in our monitor tool.
Monitor is our own health-check tool for all our microservices. Its main functionality is to check if the services are up and running and, in case something fails, it provides the ability to read logs from any service without going directly to the instance. It’s still at an early development stage, but we have big plans for implementing various monitoring tools, which will track all kind of technical information regarding the health of our microservices.
Project Setup (Tool)
Yes, we heard about Docker, but… we are avoiding it, at least for the time being. Therefore since we have quite a lot of microservices and more keep coming, we needed a way to easily make a local setup for all of them. This is a basic NodeJS application that will create a folder structure for you, clone all the microservice repositories (tools and applications as well), configures all the .env files, create databases for you, trigger migrations and dependency installs. All you need is to trigger one command and in few minutes you are ready to start working.
The App (Application)
The first frontend layer for all those microservices is our mobile application. It is based on React-Native and gives us the ability to use the same code-base for iOS and Android devices. Obviously, for Android, you will have to make additional adjustments, but at the end of the day, it’s not that much overhead, especially when compared to writing everything from scratch.
Admin Dashboard (Application)
The second frontend layer is our admin panel. It works through both gateways (admin and regular) — one to make admin requests and second to use basic requests. Admin panel will have CRUD for just about everything, as well as eventually various monitoring systems and other useful tools.
Microservices, in our case and similarly to the case of Publica, have proven to work really well with reusability. Some parts are used in almost every other microservice and they are compatible regardless of platform. Another great advantage we see is code delivery — we can work on different parts of the platform without blocking each other and deliver as soon as we are done. This was not possible with monolith apps and scheduled deployments.
Of course, not everything is as sunny. Microservice architecture has significant overhead since you have to manage a lot more servers and deployments. Luckily, there are tools like Terraform, which partly solve this issue. Another disadvantage is the infrastructure cost. It costs significantly more to run a lot of servers for microservices rather than 1 server for the single application. This can be solved with dockerization and Kubernetes, but that is something for the future.
Looking for more Blockchain solutions, check here! Scandiweb is a blockchain solutions expert. We also have completed numerous successful ICOs! Curious about details or perhaps you’re interested in what Scandiweb can do for you? Get in touch with us at email@example.com!