SERVERLESS MARIUSZ RICHTSCHEID GLIWICE, 28.01.2020
SERVERLESS NODE.JS ABOUT ME ‣ LEAD NODE.JS DEVELOPER IN THE SOFTWARE HOUSE ‣ RICHTSCHEID@GMAIL.COM ‣ LINKEDIN.COM/IN/RICHTSCHEID ‣ GITHUB.COM/BAROGRAFMARIUSZ RICHTSCHEID
SERVERLESS NODE.JS AGENDA ‣ ARE THERE SERVERS IN SERVERLESS? ‣ SHOULD I BOTHER? ‣ MOST COMMON CLOUD COMPUTING SERVICE MODELS ‣ WHICH PROVIDER TO CHOOSE? ‣ CHOOSING THE RIGHT FRAMEWORK ‣ HELLO WORLD EXAMPLE ‣ MIGRATING TRANSLATIONS SERVICE CALLED BABELSHEET TO SERVERLESS
ARE THERE SERVERS IN SERVERLESS?
SERVERLESS NODE.JS OF COURSE THERE ARE... ‣ SERVERS MANAGEMENT AND PROVISIONING OUTSOURCED TO VENDOR ‣ DYNAMIC SCALING, NO NEED FOR CAPACITY PLANNING ‣ PAY ONLY FOR WHAT YOU USE, OPTIMIZE FOR COST SAVINGS ‣ TIME TO MARKET AND EXPERIMENTATION
SERVERLESS NODE.JS WHAT ABOUT DEVOPS? ‣ A LOT OF IS OUTSOURCED BUT... ‣ YOU STILL NEED TO MONITOR YOUR APPLICATION ‣ AND HAVE STRATEGY FOR DEPLOYMENTS ‣ ALSO CONSIDER SECURITY, NETWORKING, DEBUGGING, WHOLE SYSTEM SCALING, ETC.
SHOULD I BOTHER?
SERVERLESS NODE.JS ‣ POSTLIGHT READABILITY API BEFORE SERVERLESS • $10,000 MONTHLY COST • 39 MILLION REQUESTS PER MONTH (AROUND 15 PER SECOND) ‣ AFTER SERVERLESS • NEW SERVICE NAME IS MERCURY WEB PARSER • $370 MONTHLY COST (API GATEWAY + LAMBDA)
SERVERLESS NODE.JS THERE ARE ALWAYS SOME CONS ‣ VENDOR CONTROL AND LOCK-IN ‣ STATELESS, NO LONG-RUNNING PROCESSES ‣ LIMITS ON EXECUTION TIME, MEMORY
MOST COMMON CLOUD COMPUTING SERVICE MODELS
SOURCE: HTTPS://MEDIUM.COM/@SDORZAK/WHY-SERVERLESS-IS-THE-NEW-BLACK-E4FF9E9947E0 ‣ AMAZON EC2 ‣ GOOGLE COMPUTE ENGINE ‣ AWS LAMBDA ‣ GOOGLE CLOUD FUNCTIONS ‣ AWS ELASTIC BEANSTALK ‣ HEROKU ‣ GOOGLE APP ENGINE YOU MANAGE { IAAS ‣ GOOGLE APPS ‣ SALESFORCE ‣ DROPBOX {PROVIDER PAAS FAAS SAAS
SERVERLESS NODE.JS PAAS VS FAAS ‣ SYSTEM RUNS SERVER PROCESS WHICH HANDLES REQUESTS 
 ‣ SCALING MEANS ADDING MORE PROCESSES 
 ‣ CHARGE PER RUNNING TIME ‣ NO LONG-RUNNING PROCESSES, EACH REQUEST HANDLED BY FUNCTION EXECUTION 
 ‣ SCALING MEANS EXECUTING MORE FUNCTIONS CONCURRENTLY 
 ‣ CHARGE PER EXECUTION
WHICH PROVIDER TO CHOOSE?
SERVERLESS NODE.JS INTRODUCING LAMBDA ‣ VARIOUS RUNTIMES: GO, .NET, JAVA, RUBY, PYTHON, NODE.JS (V10, V12) ‣ PRICING • 1M REQUESTS FREE • $0.20 PER 1M REQUESTS THEREAFTER • 400,000 GB-SECONDS FREE • $0.00001667 GB-SECOND THEREAFTER
SERVERLESS NODE.JS INTRODUCING LAMBDA ‣ LIMITS • MEMORY RANGE - FROM 128MB TO 3008MB • MAX EXECUTION DURATION - 15MIN • CONCURRENT EXECUTIONS - 1000 (DEFAULT, CAN BE INCREASED) • DEPLOYMENT PACKAGE SIZE - 50MB (ZIPPED) OR 250MB (UNZIPPED)
CHOOSING THE RIGHT FRAMEWORK
BUT WHY DO WE NEED FRAMEWORK AT ALL?
SERVERLESS NODE.JS PROS OF HAVING A FRAMEWORK ‣ AUTOMATES WHAT CAN BE DONE WITH AWS CONSOLE OR CLI ‣ TRANSLATES SIMPLE CONFIGURATION FILE INTO COMPLEX INFRASTRUCTURE (CLOUDFORMATION UNDER THE HOOD) ‣ USUALLY PLUGGABLE
SERVERLESS NODE.JS CHOOSING THE RIGHT FRAMEWORK ‣ PLATFORM AGNOSTIC (IN THEORY) ‣ MORE DEPLOYMENT OPTIONS (MULTIPLE PROVIDERS, LESS COMMANDS) ‣ WORSE INFRASTRUCTURE EMULATION AWS SAM ‣ FOR AWS ONLY ‣ LESS DEPLOYMENT OPTIONS ‣ BETTER INFRASTRUCTURE EMULATION (API GATEWAY, LAMBDA API, FAKE EVENTS)
SERVERLESS NODE.JS CHOOSING THE RIGHT FRAMEWORK ‣ PLATFORM AGNOSTIC (IN THEORY) ‣ MORE DEPLOYMENT OPTIONS (MULTIPLE PROVIDERS, LESS COMMANDS) ‣ WORSE INFRASTRUCTURE EMULATION AWS SAM ‣ FOR AWS ONLY ‣ LESS DEPLOYMENT OPTIONS ‣ BETTER INFRASTRUCTURE EMULATION (API GATEWAY, LAMBDA API, FAKE EVENTS)
HELLO WORLD EXAMPLE
SERVERLESS NODE.JS HELLO WORLD EXAMPLE exports.handler = async (event, context) => { return { statusCode: 200, body: 'hello world' }; }; INDEX.JS ‣EVENT • INPUT DATA FROM OTHER SOURCES ‣CONTEXT • REMAINING TIME • REQUEST ID • FUNCTION NAME • ETC.
SERVERLESS NODE.JS service: hello-world provider: name: aws runtime: nodejs12.x stage: dev region: us-east-1 functions: api: handler: index.handler events: - http: ANY / - http: 'ANY {proxy+}' SERVERLESS.YML HELLO WORLD EXAMPLE ‣EVENTS FROM: • S3 • DYNAMODB • SIMPLE NOTIFICATION SERVICE • SIMPLE EMAIL SERVICE • CLOUDFORMATION • ALEXA
SERVERLESS NODE.JS HELLO WORLD EXAMPLE
SERVERLESS NODE.JS WHAT HAS JUST HAPPENED? FUNCTIONFIRST INVOCATION RESULT COLD START CONTAINER FUNCTIONSECOND INVOCATION RESULT CONTAINER EPHEMERAL CACHE
MIGRATING BABELSHEET TO SERVERLESS
SERVERLESS NODE.JS BABELSHEET ‣ TRANSLATIONS MANAGEMENT SYSTEM ‣ GOOGLE SPREADSHEET AS A USER INTERFACE ‣ GENERATES TRANSLATIONS IN VARIOUS FORMATS THROUGH CLI OR WEB SERVER ‣ AVAILABLE AT HTTPS://GITHUB.COM/ THESOFTWAREHOUSE/BABELSHEET-JS
SERVERLESS NODE.JS BABELSHEET BEFORE FAAS
SERVERLESS NODE.JS BABELSHEET AFTER FAAS
WHAT ARE THE STEPS TO MIGRATE APP?
SERVERLESS NODE.JS THINGS TO START WITH ‣ MIGHT BE STATEFUL ‣ SUPPORTS LONG-RUNNING PROCESSES BEFORE FAAS ‣ MUST BE STATELESS ‣ NO LONG-RUNNING PROCESSES AFTER FAAS
SERVERLESS NODE.JS MORE STEPS FOR MIGRATION ‣ USE ENVIRONMENT VARIABLES TO PROVIDE CONFIG ‣ MAKE STORAGE ABSTRACTION, INJECT PROPER STORAGE IMPLEMENTATION TO IOC CONTAINER ‣ WRITE FUNCTIONS HANDLERS (MORE OR LESS GRANULAR) ‣ PREPARE STACK PROVISIONING
SERVERLESS NODE.JS API ENTRY POINT (BEFORE) import * as awilix from "awilix"; import * as dotenv from "dotenv"; import RedisStorage from "../shared/storage/redis"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(RedisStorage) }); const server = container.resolve<Server>("server").getApp(); server.listen(container.resolve("port"));
SERVERLESS NODE.JS import * as awilix from "awilix"; import * as dotenv from "dotenv"; import RedisStorage from "../shared/storage/redis"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(RedisStorage) }); const server = container.resolve<Server>("server").getApp(); server.listen(container.resolve("port")); API ENTRY POINT (BEFORE)
SERVERLESS NODE.JS import * as awilix from "awilix"; import * as dotenv from "dotenv"; import * as serverless from "serverless-http"; import DynamoDbStorage from "../shared/storage/dynamoDb"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(DynamoDbStorage) }); const server = container.resolve<Server>("server").getApp(); export const handler = serverless(server); API FUNCTION HANDLER (AFTER)
SERVERLESS NODE.JS API FUNCTION HANDLER (AFTER) import * as awilix from "awilix"; import * as dotenv from "dotenv"; import * as serverless from "serverless-http"; import DynamoDbStorage from "../shared/storage/dynamoDb"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(DynamoDbStorage) }); const server = container.resolve<Server>("server").getApp(); export const handler = serverless(server);
SERVERLESS NODE.JS PRODUCER MAIN LOGIC async function main() { const spreadsheetData = await container .resolve<GoogleSheets>("googleSheets") .fetchSpreadsheet(); const transformedData = await container .resolve<ITransformer>("transformer") .transform(spreadsheetData); container .resolve<TranslationsStorage>("translationsStorage") .setTranslations(transformedData); }
SERVERLESS NODE.JS PRODUCER ENTRY POINT (BEFORE) import * as scheduler from "node-schedule"; scheduler.scheduleJob("* * * * *", () => { main(); });
SERVERLESS NODE.JS PRODUCER FUNCTION HANDLER (AFTER) export const handler = async (event, context) => { try { await main(); } catch (error) { return { body: error.message || "Internal server error", statusCode: error.statusCode || 500 }; } return { body: JSON.stringify({ result: "ok" }), statusCode: 200 }; };
SERVERLESS NODE.JS PROVISIONING CONFIG (PROVIDER) service: serverless-translations plugins: - serverless-plugin-typescript provider: name: aws runtime: nodejs12.x stage: dev region: us-east-1 environment: DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage} iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
SERVERLESS NODE.JS PROVISIONING CONFIG (PROVIDER) service: serverless-translations plugins: - serverless-plugin-typescript provider: name: aws runtime: nodejs12.x stage: dev region: us-east-1 environment: DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage} iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
SERVERLESS NODE.JS PROVISIONING CONFIG (PROVIDER) service: serverless-translations plugins: - serverless-plugin-typescript provider: name: aws runtime: nodejs12.x stage: dev region: us-east-1 environment: DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage} iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
SERVERLESS NODE.JS PROVISIONING CONFIG (FUNCTIONS) functions: api: handler: src/api/serverless.handler events: - http: ANY / - http: "ANY {proxy+}" producer: handler: src/producer/serverless.handler environment: token: ${ssm:token~true} CLIENT_ID: ${ssm:CLIENT_ID~true} CLIENT_SECRET: ${ssm:CLIENT_SECRET~true} events: - schedule: rate(5 minutes)
SERVERLESS NODE.JS PROVISIONING CONFIG (FUNCTIONS) functions: api: handler: src/api/serverless.handler events: - http: ANY / - http: "ANY {proxy+}" producer: handler: src/producer/serverless.handler environment: token: ${ssm:token~true} CLIENT_ID: ${ssm:CLIENT_ID~true} CLIENT_SECRET: ${ssm:CLIENT_SECRET~true} events: - schedule: rate(5 minutes)
SERVERLESS NODE.JS PROVISIONING CONFIG (FUNCTIONS) functions: api: handler: src/api/serverless.handler events: - http: ANY / - http: "ANY {proxy+}" producer: handler: src/producer/serverless.handler environment: token: ${ssm:token~true} CLIENT_ID: ${ssm:CLIENT_ID~true} CLIENT_SECRET: ${ssm:CLIENT_SECRET~true} events: - schedule: rate(5 minutes)
SERVERLESS NODE.JS PROVISIONING CONFIG (RESOURCES) resources: Resources: TranslationsDynamoDbTable: Type: "AWS::DynamoDB::Table" DeletionPolicy: Delete Properties: AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 TableName: ${self:provider.environment.DYNAMODB_TABLE}
SERVERLESS NODE.JS AWS CONSOLE PREVIEW AFTER DEPLOY
SERVERLESS NODE.JS INVOKING A FUNCTION
SERVERLESS NODE.JS CHECKING APP METRICS
SERVERLESS NODE.JS OPTIMIZATION STEPS ‣ HTTP CACHE ON API GATEWAY (REDUCE TIME, COST) ‣ LOWER MEMORY LIMIT ‣ USE EXECUTION CONTEXT FOR LOCAL CACHE ‣ USE FAST STORAGE SOLUTION, E.G. REDIS
SERVERLESS NODE.JS SUMMARY ‣ CALCULATE IF IT IS FOR YOU, CONSIDER PRICING AND LIMITATIONS ‣ CHOOSE PROPER PROVIDER AND FRAMEWORK ‣ PREPARE YOUR APP FOR GOING SERVERLESS ‣ WRITE FUNCTION HANDLERS, PROVISIONING CONFIG ‣ DEPLOY, OPTIMIZE, REPEAT
SERVERLESS NODE.JS WORTH KNOWING ‣ AWS STEP FUNCTIONS ‣ LAMBDA LAYERS ‣ BLUE/GREEN DEPLOYMENTS ‣ GRAPHQL ENDPOINTS ‣ GOOGLE CLOUD RUN (KNATIVE)
THANK YOU! ICONS MADE BY ICON POND FROM WWW.FLATICON.COM 
HTTP://TSH.IO/MICROSERVICES
NEWSLETTER FOR DEVS AND TECH LEADERS HTTPS://TSH.IO/NEWSLETTER

Serverless architecture: introduction & first steps

  • 1.
  • 2.
    SERVERLESS NODE.JS ABOUT ME ‣LEAD NODE.JS DEVELOPER IN THE SOFTWARE HOUSE ‣ RICHTSCHEID@GMAIL.COM ‣ LINKEDIN.COM/IN/RICHTSCHEID ‣ GITHUB.COM/BAROGRAFMARIUSZ RICHTSCHEID
  • 3.
    SERVERLESS NODE.JS AGENDA ‣ ARETHERE SERVERS IN SERVERLESS? ‣ SHOULD I BOTHER? ‣ MOST COMMON CLOUD COMPUTING SERVICE MODELS ‣ WHICH PROVIDER TO CHOOSE? ‣ CHOOSING THE RIGHT FRAMEWORK ‣ HELLO WORLD EXAMPLE ‣ MIGRATING TRANSLATIONS SERVICE CALLED BABELSHEET TO SERVERLESS
  • 4.
    ARE THERE SERVERSIN SERVERLESS?
  • 5.
    SERVERLESS NODE.JS OF COURSETHERE ARE... ‣ SERVERS MANAGEMENT AND PROVISIONING OUTSOURCED TO VENDOR ‣ DYNAMIC SCALING, NO NEED FOR CAPACITY PLANNING ‣ PAY ONLY FOR WHAT YOU USE, OPTIMIZE FOR COST SAVINGS ‣ TIME TO MARKET AND EXPERIMENTATION
  • 6.
    SERVERLESS NODE.JS WHAT ABOUTDEVOPS? ‣ A LOT OF IS OUTSOURCED BUT... ‣ YOU STILL NEED TO MONITOR YOUR APPLICATION ‣ AND HAVE STRATEGY FOR DEPLOYMENTS ‣ ALSO CONSIDER SECURITY, NETWORKING, DEBUGGING, WHOLE SYSTEM SCALING, ETC.
  • 7.
  • 8.
    SERVERLESS NODE.JS ‣ POSTLIGHTREADABILITY API BEFORE SERVERLESS • $10,000 MONTHLY COST • 39 MILLION REQUESTS PER MONTH (AROUND 15 PER SECOND) ‣ AFTER SERVERLESS • NEW SERVICE NAME IS MERCURY WEB PARSER • $370 MONTHLY COST (API GATEWAY + LAMBDA)
  • 9.
    SERVERLESS NODE.JS THERE AREALWAYS SOME CONS ‣ VENDOR CONTROL AND LOCK-IN ‣ STATELESS, NO LONG-RUNNING PROCESSES ‣ LIMITS ON EXECUTION TIME, MEMORY
  • 10.
    MOST COMMON CLOUDCOMPUTING SERVICE MODELS
  • 11.
    SOURCE: HTTPS://MEDIUM.COM/@SDORZAK/WHY-SERVERLESS-IS-THE-NEW-BLACK-E4FF9E9947E0 ‣ AMAZONEC2 ‣ GOOGLE COMPUTE ENGINE ‣ AWS LAMBDA ‣ GOOGLE CLOUD FUNCTIONS ‣ AWS ELASTIC BEANSTALK ‣ HEROKU ‣ GOOGLE APP ENGINE YOU MANAGE { IAAS ‣ GOOGLE APPS ‣ SALESFORCE ‣ DROPBOX {PROVIDER PAAS FAAS SAAS
  • 12.
    SERVERLESS NODE.JS PAAS VSFAAS ‣ SYSTEM RUNS SERVER PROCESS WHICH HANDLES REQUESTS 
 ‣ SCALING MEANS ADDING MORE PROCESSES 
 ‣ CHARGE PER RUNNING TIME ‣ NO LONG-RUNNING PROCESSES, EACH REQUEST HANDLED BY FUNCTION EXECUTION 
 ‣ SCALING MEANS EXECUTING MORE FUNCTIONS CONCURRENTLY 
 ‣ CHARGE PER EXECUTION
  • 13.
  • 16.
    SERVERLESS NODE.JS INTRODUCING LAMBDA ‣VARIOUS RUNTIMES: GO, .NET, JAVA, RUBY, PYTHON, NODE.JS (V10, V12) ‣ PRICING • 1M REQUESTS FREE • $0.20 PER 1M REQUESTS THEREAFTER • 400,000 GB-SECONDS FREE • $0.00001667 GB-SECOND THEREAFTER
  • 17.
    SERVERLESS NODE.JS INTRODUCING LAMBDA ‣LIMITS • MEMORY RANGE - FROM 128MB TO 3008MB • MAX EXECUTION DURATION - 15MIN • CONCURRENT EXECUTIONS - 1000 (DEFAULT, CAN BE INCREASED) • DEPLOYMENT PACKAGE SIZE - 50MB (ZIPPED) OR 250MB (UNZIPPED)
  • 18.
  • 19.
    BUT WHY DOWE NEED FRAMEWORK AT ALL?
  • 20.
    SERVERLESS NODE.JS PROS OFHAVING A FRAMEWORK ‣ AUTOMATES WHAT CAN BE DONE WITH AWS CONSOLE OR CLI ‣ TRANSLATES SIMPLE CONFIGURATION FILE INTO COMPLEX INFRASTRUCTURE (CLOUDFORMATION UNDER THE HOOD) ‣ USUALLY PLUGGABLE
  • 21.
    SERVERLESS NODE.JS CHOOSING THERIGHT FRAMEWORK ‣ PLATFORM AGNOSTIC (IN THEORY) ‣ MORE DEPLOYMENT OPTIONS (MULTIPLE PROVIDERS, LESS COMMANDS) ‣ WORSE INFRASTRUCTURE EMULATION AWS SAM ‣ FOR AWS ONLY ‣ LESS DEPLOYMENT OPTIONS ‣ BETTER INFRASTRUCTURE EMULATION (API GATEWAY, LAMBDA API, FAKE EVENTS)
  • 22.
    SERVERLESS NODE.JS CHOOSING THERIGHT FRAMEWORK ‣ PLATFORM AGNOSTIC (IN THEORY) ‣ MORE DEPLOYMENT OPTIONS (MULTIPLE PROVIDERS, LESS COMMANDS) ‣ WORSE INFRASTRUCTURE EMULATION AWS SAM ‣ FOR AWS ONLY ‣ LESS DEPLOYMENT OPTIONS ‣ BETTER INFRASTRUCTURE EMULATION (API GATEWAY, LAMBDA API, FAKE EVENTS)
  • 23.
  • 24.
    SERVERLESS NODE.JS HELLO WORLDEXAMPLE exports.handler = async (event, context) => { return { statusCode: 200, body: 'hello world' }; }; INDEX.JS ‣EVENT • INPUT DATA FROM OTHER SOURCES ‣CONTEXT • REMAINING TIME • REQUEST ID • FUNCTION NAME • ETC.
  • 25.
    SERVERLESS NODE.JS service: hello-world provider: name:aws runtime: nodejs12.x stage: dev region: us-east-1 functions: api: handler: index.handler events: - http: ANY / - http: 'ANY {proxy+}' SERVERLESS.YML HELLO WORLD EXAMPLE ‣EVENTS FROM: • S3 • DYNAMODB • SIMPLE NOTIFICATION SERVICE • SIMPLE EMAIL SERVICE • CLOUDFORMATION • ALEXA
  • 26.
  • 27.
    SERVERLESS NODE.JS WHAT HASJUST HAPPENED? FUNCTIONFIRST INVOCATION RESULT COLD START CONTAINER FUNCTIONSECOND INVOCATION RESULT CONTAINER EPHEMERAL CACHE
  • 28.
  • 29.
    SERVERLESS NODE.JS BABELSHEET ‣ TRANSLATIONSMANAGEMENT SYSTEM ‣ GOOGLE SPREADSHEET AS A USER INTERFACE ‣ GENERATES TRANSLATIONS IN VARIOUS FORMATS THROUGH CLI OR WEB SERVER ‣ AVAILABLE AT HTTPS://GITHUB.COM/ THESOFTWAREHOUSE/BABELSHEET-JS
  • 30.
  • 31.
  • 32.
    WHAT ARE THESTEPS TO MIGRATE APP?
  • 33.
    SERVERLESS NODE.JS THINGS TOSTART WITH ‣ MIGHT BE STATEFUL ‣ SUPPORTS LONG-RUNNING PROCESSES BEFORE FAAS ‣ MUST BE STATELESS ‣ NO LONG-RUNNING PROCESSES AFTER FAAS
  • 34.
    SERVERLESS NODE.JS MORE STEPSFOR MIGRATION ‣ USE ENVIRONMENT VARIABLES TO PROVIDE CONFIG ‣ MAKE STORAGE ABSTRACTION, INJECT PROPER STORAGE IMPLEMENTATION TO IOC CONTAINER ‣ WRITE FUNCTIONS HANDLERS (MORE OR LESS GRANULAR) ‣ PREPARE STACK PROVISIONING
  • 35.
    SERVERLESS NODE.JS API ENTRYPOINT (BEFORE) import * as awilix from "awilix"; import * as dotenv from "dotenv"; import RedisStorage from "../shared/storage/redis"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(RedisStorage) }); const server = container.resolve<Server>("server").getApp(); server.listen(container.resolve("port"));
  • 36.
    SERVERLESS NODE.JS import *as awilix from "awilix"; import * as dotenv from "dotenv"; import RedisStorage from "../shared/storage/redis"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(RedisStorage) }); const server = container.resolve<Server>("server").getApp(); server.listen(container.resolve("port")); API ENTRY POINT (BEFORE)
  • 37.
    SERVERLESS NODE.JS import *as awilix from "awilix"; import * as dotenv from "dotenv"; import * as serverless from "serverless-http"; import DynamoDbStorage from "../shared/storage/dynamoDb"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(DynamoDbStorage) }); const server = container.resolve<Server>("server").getApp(); export const handler = serverless(server); API FUNCTION HANDLER (AFTER)
  • 38.
    SERVERLESS NODE.JS API FUNCTIONHANDLER (AFTER) import * as awilix from "awilix"; import * as dotenv from "dotenv"; import * as serverless from "serverless-http"; import DynamoDbStorage from "../shared/storage/dynamoDb"; import createContainer from "./container"; import Server from "./server/server"; dotenv.config(); const container = createContainer({ storage: awilix.asClass(DynamoDbStorage) }); const server = container.resolve<Server>("server").getApp(); export const handler = serverless(server);
  • 39.
    SERVERLESS NODE.JS PRODUCER MAINLOGIC async function main() { const spreadsheetData = await container .resolve<GoogleSheets>("googleSheets") .fetchSpreadsheet(); const transformedData = await container .resolve<ITransformer>("transformer") .transform(spreadsheetData); container .resolve<TranslationsStorage>("translationsStorage") .setTranslations(transformedData); }
  • 40.
    SERVERLESS NODE.JS PRODUCER ENTRYPOINT (BEFORE) import * as scheduler from "node-schedule"; scheduler.scheduleJob("* * * * *", () => { main(); });
  • 41.
    SERVERLESS NODE.JS PRODUCER FUNCTIONHANDLER (AFTER) export const handler = async (event, context) => { try { await main(); } catch (error) { return { body: error.message || "Internal server error", statusCode: error.statusCode || 500 }; } return { body: JSON.stringify({ result: "ok" }), statusCode: 200 }; };
  • 42.
    SERVERLESS NODE.JS PROVISIONING CONFIG(PROVIDER) service: serverless-translations plugins: - serverless-plugin-typescript provider: name: aws runtime: nodejs12.x stage: dev region: us-east-1 environment: DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage} iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
  • 43.
    SERVERLESS NODE.JS PROVISIONING CONFIG(PROVIDER) service: serverless-translations plugins: - serverless-plugin-typescript provider: name: aws runtime: nodejs12.x stage: dev region: us-east-1 environment: DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage} iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
  • 44.
    SERVERLESS NODE.JS PROVISIONING CONFIG(PROVIDER) service: serverless-translations plugins: - serverless-plugin-typescript provider: name: aws runtime: nodejs12.x stage: dev region: us-east-1 environment: DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage} iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
  • 45.
    SERVERLESS NODE.JS PROVISIONING CONFIG(FUNCTIONS) functions: api: handler: src/api/serverless.handler events: - http: ANY / - http: "ANY {proxy+}" producer: handler: src/producer/serverless.handler environment: token: ${ssm:token~true} CLIENT_ID: ${ssm:CLIENT_ID~true} CLIENT_SECRET: ${ssm:CLIENT_SECRET~true} events: - schedule: rate(5 minutes)
  • 46.
    SERVERLESS NODE.JS PROVISIONING CONFIG(FUNCTIONS) functions: api: handler: src/api/serverless.handler events: - http: ANY / - http: "ANY {proxy+}" producer: handler: src/producer/serverless.handler environment: token: ${ssm:token~true} CLIENT_ID: ${ssm:CLIENT_ID~true} CLIENT_SECRET: ${ssm:CLIENT_SECRET~true} events: - schedule: rate(5 minutes)
  • 47.
    SERVERLESS NODE.JS PROVISIONING CONFIG(FUNCTIONS) functions: api: handler: src/api/serverless.handler events: - http: ANY / - http: "ANY {proxy+}" producer: handler: src/producer/serverless.handler environment: token: ${ssm:token~true} CLIENT_ID: ${ssm:CLIENT_ID~true} CLIENT_SECRET: ${ssm:CLIENT_SECRET~true} events: - schedule: rate(5 minutes)
  • 48.
    SERVERLESS NODE.JS PROVISIONING CONFIG(RESOURCES) resources: Resources: TranslationsDynamoDbTable: Type: "AWS::DynamoDB::Table" DeletionPolicy: Delete Properties: AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 TableName: ${self:provider.environment.DYNAMODB_TABLE}
  • 49.
    SERVERLESS NODE.JS AWS CONSOLEPREVIEW AFTER DEPLOY
  • 50.
  • 51.
  • 52.
    SERVERLESS NODE.JS OPTIMIZATION STEPS ‣HTTP CACHE ON API GATEWAY (REDUCE TIME, COST) ‣ LOWER MEMORY LIMIT ‣ USE EXECUTION CONTEXT FOR LOCAL CACHE ‣ USE FAST STORAGE SOLUTION, E.G. REDIS
  • 53.
    SERVERLESS NODE.JS SUMMARY ‣ CALCULATEIF IT IS FOR YOU, CONSIDER PRICING AND LIMITATIONS ‣ CHOOSE PROPER PROVIDER AND FRAMEWORK ‣ PREPARE YOUR APP FOR GOING SERVERLESS ‣ WRITE FUNCTION HANDLERS, PROVISIONING CONFIG ‣ DEPLOY, OPTIMIZE, REPEAT
  • 54.
    SERVERLESS NODE.JS WORTH KNOWING ‣AWS STEP FUNCTIONS ‣ LAMBDA LAYERS ‣ BLUE/GREEN DEPLOYMENTS ‣ GRAPHQL ENDPOINTS ‣ GOOGLE CLOUD RUN (KNATIVE)
  • 55.
    THANK YOU! ICONS MADEBY ICON POND FROM WWW.FLATICON.COM 
  • 56.
  • 57.
    NEWSLETTER FOR DEVSAND TECH LEADERS HTTPS://TSH.IO/NEWSLETTER