# nodejs: Concept ## Event loop: Blocking vs Non-Blocking ![image](https://i.imgur.com/qpDiVlA.png) https://nodejs.org/en/docs/guides/blocking-vs-non-blocking https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick ### blocking sample In main thread ```typescript import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } blocking() { const now = new Date().getTime(); while (new Date().getTime() < now + 10000) {} return {}; } } ``` This service will block the main thread to handle this 10000 millisecond work ### with non-blocking revise We could turn blocking code into promise to allow cpu release the code on blocking code ```typescript import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } blocking() { const now = new Date().getTime(); while (new Date().getTime() < now + 10000) {} return {}; } async nonBlocking() { return new Promise(async (resolve) => { setTimeout(() => { resolve({}); }, 100000); }); } } ``` add non-blocking-route ```typescript import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() getHello(): string { return this.appService.getHello(); } @Get('blocking') blocking() { return this.appService.blocking(); } @Get('non-blocking') async nonBlocking() { return this.appService.nonBlocking(); } } ``` This way the non-blocking code will auto dispatch by event loop and will not blocking other code ## Concurrency In Nodejs, Concurrency means the Event loop ability that handle callback after finish another callback ### Parallel Parallel is ability to handle multiple task at the sample time ### sample the promise all (parallel the promises) ```typescript import { Injectable, Logger } from '@nestjs/common'; @Injectable() export class AppService { private readonly logger = new Logger(AppService.name); getHello(): string { return 'Hello World!'; } blocking() { const now = new Date().getTime(); while (new Date().getTime() < now + 10000) {} return {}; } async nonBlocking() { return new Promise(async (resolve) => { setTimeout(() => { resolve({}); }, 100000); }); } async promises() { const results = []; for (let i = 0; i < 10; i++) { results.push(await this.sleep()); } return results; } async promisesParallel() { const results = []; for (let i = 0; i < 10; i++) { results.push(this.sleep()); } return Promise.all(results); } private async sleep() { return new Promise((resolve) => { this.logger.log('Start sleep'); setTimeout(() => { this.logger.log('Sleep complete'); resolve({}); }, 1000); }); } } ``` add route for sample ```typescript import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() getHello(): string { return this.appService.getHello(); } @Get('blocking') blocking() { return this.appService.blocking(); } @Get('non-blocking') async nonBlocking() { return this.appService.nonBlocking(); } @Get('promises') async promises() { return this.appService.promises(); } @Get('promises-parallel') async promisesParallel() { return this.appService.promisesParallel(); } } ``` however, the promise has memory cost thus, could not spread no limit promises parallel usaualy group related datasource promise together And CPU-intensive job could not use this way to scale ## install autocannon to do load testing ```shell pnpm i -S autocannon ``` load testing 10000 concurrent request with timeout 30s duration 60s ```shell pnpm autocannon localhost:3000/promises -c 100000 -t 30 -d 60 ``` ## With Mutiple core the cpu bound could load balance the cpu intensive job create deployment yaml by kubectl ```shell helm create scale-nodejs-concept cd k8s/scale-nodejs-concept/template kubectl create deployment scale-nodejs-concept --image=yuanyu90221/scale-nodejs-concept:dev --port 3000 --dry-run=client -o yaml > deployment.yml kubectl create svc nodeport scale-nodejs-concept --tcp=3000:3000 --dry-run=client -o yaml > service.yml ```