1 of 39

Managing shared state in Node.js without compromising on data lose and security issues

2 of 39

3 of 39

Backend Call

4 of 39

Backend Call

DB Query

5 of 39

Backend Call

DB Query

Backend Call

6 of 39

7 of 39

Practical Examples

X-request-id

Aspects

Experiments

Cache

8 of 39

Local State

9 of 39

Requirements

Maintain context throughout an async flow

Ensure accessibility of the context only within the same async flow

10 of 39

Async Flow

Backend �API Call

Backend �API Call

DB Query

Requset

Response

11 of 39

Ideas?

12 of 39

Global Object?

13 of 39

Global Object?

14 of 39

How the event loop works?

15 of 39

Backend �API Call 2

DB Query 2

Backend �API Call 2

Response 1

Response 2

Request 1

Request 2

Main Thread

Backend �API Call 1

Backend �API Call 1

DB Query 1

16 of 39

How Multi-Threading works?

17 of 39

Thread 2

Multi-Threading

Backend �API Call 1

Backend �API Call 1

DB Query 1

Request 1

Response 1

Backend �API Call 2

Backend �API Call 2

DB Query 2

Request 2

Response 2

Thread 1

18 of 39

VS

Thread 2

Multi-Threading

Backend �API Call 1

Backend �API Call 1

DB Query 1

Request 1

Response 1

Backend �API Call 2

Backend �API Call 2

DB Query 2

Request 2

Response 2

Thread 1

Event-Loop

Backend �API Call 1

DB Query 1

Backend �API Call 2

Backend �API Call 1

DB Query 2

Backend �API Call 2

Response 1

Response 2

Request 1

Request 2

Main Thread

19 of 39

Thread Local Storage

20 of 39

If you can’t solve a problem, then there is an easier problem you can solve: find it.”

- George Polya

21 of 39

Multi-Threading in Node?

22 of 39

Multi-Threading in Node?

A new thread for each incoming request

23 of 39

Multi-Threading in Node?

A new thread for each incoming request

Child proccess

24 of 39

Multi-Threading in Node?

A new thread for each incoming request

Child proccess Worker threads

25 of 39

Multi-Threading in Node?

A new thread for each incoming request

Child proccess Worker threads Clusters

26 of 39

27 of 39

“Workers (threads) are useful for performing CPU-intensive JavaScript operations. ��They do not help much with I/O-intensive work. ��The Node.js built-in asynchronous I/O operations are more efficient than Workers can be.”

- docs

28 of 39

Built in Node API

The solution

29 of 39

A built-in Node.js API that provides a way of propagating the context of the current async operation through the call chain without the need to explicitly pass it as a function parameter. ��It is similar to thread-local storage in other languages.

AsyncLocalStorage

30 of 39

31 of 39

32 of 39

33 of 39

34 of 39

Performance

35 of 39

While you can create your own implementation on top of the node:async_hooks module, AsyncLocalStorage should be preferred as it is a performant and memory safe implementation that involves significant optimizations that are non-obvious to implement.”

- docs

36 of 39

       async_hooks Performance Analysis

37 of 39

Context Loss

In most cases, AsyncLocalStorage works without issues. In rare situations, the current store is lost in one of the asynchronous operations.��If your code is promise-based there should be no problem otherwise if it is callback-based, it is enough to promisify it with util.promisify() so it starts working with native promises.

38 of 39

Summary

AsyncLocalStorage is the best option for a TLS-like solution to store a local context between an async flow. �

Before using it you should be aware of its pitfalls�

  • possible context loss if you have a callback-based API�
  • performance impact

39 of 39

Thank You