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