Skip to content

Latest commit

 

History

History
394 lines (269 loc) · 10.6 KB

section-02.md

File metadata and controls

394 lines (269 loc) · 10.6 KB

Section 02: A Mini-Microservices App

Table of Contents

App Overview

Goals

  • Get a taste of a microservices architecture
  • Build as much as possible from scratch

What services should we create?

  • For now, we will create one separate service for each resource in our app

⬆ back to top

Project Setup

Initial App Setup

  • Generate a new React App using Create-React-App
  • Create an Express-based project for the Posts Service
  • Create an Express-based project for the Comments Service

⬆ back to top

Posts Service Creation

⬆ back to top

Implementing a Comments Service

⬆ back to top

React Project Setup

⬆ back to top

Request Minimization Strategies

Notes on Sync Communication

Pro Con
Conceptually easy to understand! Introduces a dependency between services
If any inter-service request fails, the overall request fails
The entire request is only as fast as the slowest request
Can easily introduce webs of requests

⬆ back to top

An Async Solution

Notes on Async Communication

Pros Cons
Query Service has zero dependencies on other services! Data duplication.
Query Service will be extremely fast! Harder to understand

⬆ back to top

Common Questions Around Async Events

Wait, so you're saying we need to create a new service every time we need to join some data?!?!?!?!?!?

Absolutely not! In reality, might not even have posts and comments in separate services in the first place

Who cares that each service is independent?

Independent services + the reliability that brings is one of the core reasons of using microservices in the first place

This is so over the top complicated for little benefit

Seems that way now! Adding in some features starts to get really easy when we use this architecture

This system won't correctly in the following scenario....

There are some very special things we need to consider with this design. I've got solutions for most (maybe?) of the concerns you may have

⬆ back to top

Event Bus Overview

Event Bus

  • Many different implementations. RabbitMQ, Kafka, NATS...
  • Receives events, publishes them to listeners
  • Many different subtle features that make async communication way easier or way harder
  • We are going to build our own event bus using Express. It will not implement the vast majority of features a normal bus has.
  • Yes, for our next app we will use a production grade, open source event bus

⬆ back to top

A Basic Event Bus Implementation

// event-bus/index.js
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');

const app = express();
app.use(bodyParser.json());

app.post('/events', (req, res) => {
  const event = req.body;

  axios.post('http://localhost:4000/events', event);
  axios.post('http://localhost:4001/events', event);
  axios.post('http://localhost:4002/events', event);

  res.send({ status: 'OK' });
});

app.listen(4005, () => {
  console.log('Listening on 4005');
});

⬆ back to top

Emitting Post Creation Events

// posts/index.js
const posts = {};
app.post('/posts', async (req, res) => {
  const id = randomBytes(4).toString('hex');
  const { title } = req.body;

  posts[id] = {
    id,
    title
  };

  await axios.post('http://localhost:4005/events', {
    type: 'PostCreated',
    data: {
      id,
      title
    }
  });

  res.status(201).send(posts[id]);
});

⬆ back to top

Emitting Comment Creation Events

// comments/index.js
const commentsByPostId = {};
app.post('/posts/:id/comments', async (req, res) => {
  const commentId = randomBytes(4).toString('hex');
  const { content } = req.body;

  const comments = commentsByPostId[req.params.id] || [];
  comments.push({ id: commentId, content });
  commentsByPostId[req.params.id] = comments;

  await axios.post('http://localhost:4005/events', {
    type: 'CommentCreated',
    data: {
      id: commentId,
      content,
      postId: req.params.id
    }
  });

  res.status(201).send(comments);
});

⬆ back to top

Receiving Events

// posts/index.js
// comments/index.js
app.post('/events', (req, res) => {
  console.log('Received Event', req.body.type);

  res.send({});
});

⬆ back to top

Creating the Data Query Service

// query/index.js
app.get('/posts', (req, res) => {});
app.post('/events', (req, res) => {});

⬆ back to top

Parsing Incoming Events

// query/index.js
app.get('/posts', (req, res) => {
  res.send(posts);
});

app.post('/events', (req, res) => {
  const { type, data } = req.body;

  if (type === 'PostCreated') {
    const { id, title } = data;

    posts[id] = { id, title, comments: [] };
  }

  if (type === 'CommentCreated') {
    const { id, content, postId } = data;

    const post = posts[postId];
    post.comments.push({ id, content });
  }

  console.log(posts);

  res.send({});
});

⬆ back to top

Using the Query Service

⬆ back to top

Adding a Simple Feature

Feature Request

  • Add in comment moderation.
  • Flag comments that contain the word 'orange'.

Feature Clarifications

  • Super easy to implement in the React app, but not if the filter list changes frequently
  • Super easy to implement in the existing comments service, but let's assume we want to add a new service
  • It might take a long time for the new service to moderate a comment.

⬆ back to top

Issues with Comment Filtering

⬆ back to top

A Second Approach

  • The query service is about presentation logic
  • It is joining two resources right now (posts and comments), but it might join 10!
  • Does it make sense for a presentation service to understand how to process a very precise update?

⬆ back to top

How to Handle Resource Updates

⬆ back to top

Creating the Moderation Service

// moderation/index.js
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');

const app = express();
app.use(bodyParser.json());

app.post('/events', (req, res) => {});

app.listen(4003, () => {
  console.log('Listening on 4003');
});

⬆ back to top

Adding Comment Moderation

⬆ back to top

Handling Moderation

⬆ back to top

Updating Comment Content

⬆ back to top

Dealing with Missing Events

⬆ back to top