10 minute learns

Reactive Serverless Architecture

 

Learn how and why a reactive & serverless architecure is one of the best ways to approach modern product engineering.

What

Previously unachievable, a reactive serverless architecture built using websockets, an api gateway, database streams and an army of reactive serverless functions in between, provides:

  • end-to-end asynchronicity across your entire product ecosystem
  • an army of ephemeral micro functions that perform your business logic in separation and react to user and system events instantly
  • autonomous, real-time updates driven from the data layer to your users

    ...all without a server!

Why

  • Significantly less $$$
  • Smart Architecture
  • Brilliant Engineers

Significantly Less $$$

💸 Serverless let's you pay for what you use, let's look at the numbers:

Small Blog Application
First 1,000,000 requests [$0, free tier] +
Next 5,000,000 requests * 0.0000002
= $1 per 6,000,000 requests

Small Banking App
100000 users *
50 requests each per day *
365 days per year *

$0.0000002 per request
= $364.80 per 1,825,000,000 requests

🚌 Reactive / PubSub architecture - drive updates from the data layer, through an army of ephemeral functions to your users autonomously based on their own changes.

Benefits:

  • reduced complexity everywhere
  • scale horizontally: tiny functions = tiny responsibility
  • decouple everything, offload software design patterns to architecture
  • production, quicker: deploy only changed code without disrupting rest of ecosystem
  • architecture changes + migrations made easier
  • legacy will no longer be a failure of design

Smart Architecture

🧮 Let your engineers focus on customer needs and building a far superior and more robust product.

 

Benefits:

  • think less, do more: less complexity means easier on-boarding, less chances of error and better focus
  • beat the competition, faster experimentation: push new features, rather than tech debt and fighting fires
  • support made easy: full-stack understanding and quicker response to issues as they occurr
  • everyone is responsible for success of the products and services

Brilliant Engineers

How

  • Services:
    • API (e.g., AWS API Gateway)
    • Serverless Functions (e.g., AWS Lambda)
    • Database w/Streams (e.g., AWS DynamoDB)
  • Client/s:
    • Observables/streams (e.g., RxJS, Kefir)
// Some custom authoriser which uses auth_key header/queryParam
// and passes user claims onto next function, such as $connect
function customAuthoriser () { ... }

// Websockets $connect action to create a connection for authenticated 
// user + inserts into db using user_id as key
function connect (authClaims) { ... }

// Websockets $disconnect action to remove connection/s 
// for specific user or set of users
function disconnect () { ... }

// Websockets $defaultMessage action to gracefully handle requests
// which are not supported by API
function defaultMessage () { ... }

// Send a message to a connection
// e.g., chat room, which certain user is a part of needs to be notified
// when new messages are sent there
function sendMessage (connectionId, message) { ... }

// Database change stream broadcast event
function broadcast (event) { ... }

Websockets Lambdas

# CloudFormation template
MainTable:
  Type: 'AWS::DynamoDB::Table'
  DeletionPolicy: Retain
  Properties:
    TableName: ${self:provider.environment.mainTable}-${self:provider.stage}
    StreamSpecification:
      StreamViewType: NEW_AND_OLD_IMAGES
    ...

DynamoDB Streams + Lambdas

export async function broadcast (
  event: DynamoDBStreamEvent,
  context: Context,
  callback: Callback
) {
  const record = event.Records[0].dynamodb;

  // do something with record here
  // e.g., find users who are associated with entity
  // and broadcast change if any open websockets connections
  // match user ids

  ...
}

Web app using JavaScript Observables

// https://rxjs-dev.firebaseapp.com/api/webSocket/webSocket
import {webSocket} from 'rxjs/webSocket';

function setup () {
  const apiGatewayWebsocketUrl = 
    'wss://abcd-1234.ap-southeast.aws.amazon.com';
  const subject = webSocket(apiGatewayWebsocketUrl);
    
  subject.subscribe(
    // Called whenever there is a message from the server
    msg => console.log('message received: ' + msg),

    // Called if at any point WebSocket API signals some kind of error
    err => console.log(err),

    // Called when connection is closed (for whatever reason)
    () => console.log('complete')
  );
}

iOS app using RxStarscream Observables

// https://github.com/RxSwiftCommunity/RxStarscream
import RxStarscream

socket = WebSocket(url: URL(string: "ws://localhost:8080/")!)
socket.connect()

socket.rx.response.subscribe(onNext: { (response: WebSocketEvent) in
  switch response {
    case .connected:
      print("Connected")
    case .disconnected(let error):
      print("Disconnected with optional error : \(error)")
    case .message(let msg):
      print("Message : \(msg)")
    case .data(_):
      print("Data")
    case .pong:
      print("Pong")
  }
}).disposed(by: disposeBag)

Resources

Reactive Serverless Architecture

By Matt Rowles

Reactive Serverless Architecture

Learn how an end-to-end, asynchronous & completely serverless architecture can be stood up in no time at all - and why you should do it.

  • 97