Luciano Mammino PRO
Cloud developer, entrepreneur, fighter, butterfly maker! #nodejs #javascript - Author of https://www.nodejsdesignpatterns.com , Founder of https://fullstackbulletin.com
Luciano Mammino (@loige)
2023-04-13
👋 I'm Luciano (🇮🇹🍕🍝🤌)
👨💻 Senior Architect @ fourTheorem
📔 Co-Author of Node.js Design Patterns 👉
Grab the slides
✉️ Reach out to us at hello@fourTheorem.com
😇 We are always looking for talent: fth.link/careers
We can help with:
Cloud Migrations
Training & Cloud enablement
Building high-performance serverless applications
Cutting cloud costs
We host a weekly podcast about AWS
* Yes, I still have access 😇
*
A way of running applications in the cloud
Of course, there are servers
... we just don't have to think about them
You pay for what you use
Small units of compute (functions), triggered by events
More focus on the business logic (generally)
Increased team agility (mostly)
Automatic scalability (sorta)
Not a universal solution, but it can work well in many situations!
Opinion: We will definitely see MOAR SERVERLESS in the future!
FaaS offering in AWS
Can be triggered by different kinds of events
Hello, I am the "Lambda Engine"
Oh, a new event!
Event
Is there a Lambda associated to it?
Event
Yes, here's one! So let's trigger it!
Event
But, we don't have any instance ready!
Event
Let's create a new one!
Event
Let's use the code stored in this bucket!
Event
Let's use the code stored in this bucket!
Event
Now we can let this instance process the event!
Event
Now we can let this instance process the event!
Event
It's working really hard!
Event
🥵
Nice! Another event!
Event
🥵
Event
Our only instance is busy... we need a new one!
Event
🥵
Event
Event
🥵
Event
Event
🥵
Event
It can now take care of the event!
Event
🥵
Event
🥵
Event
🥳
Event
🥵
Response
Nice! The first lambda has completed
Event
🥵
Response
Let's forward its response back!
Event
🥵
Event
🥵
The 1st instance has been idle for a while
😴
Event
🥵
We can destroy it
😴
Event
🥵
Event
🥳
Response
Nice! The second lambda has completed
Response
Oh, a new event!
Event
There's an instance ready for it!
Event
Event
🥵
Event
🥳
Response
Response
😴
Summary
Response
Event
Max code size: 250 MB
docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html
* With the new Response Streaming feature the response limit goes up to 20 MB (with some extra 💸)
Cost = Allocated Memory 𝒙 time
Cost = Allocated Memory 𝒙 time
512 MB = $0.0000000083/ms
Executing a lambda for 15 mins...
0.0000000083 * 900000 = 0.007 $
You don't explicitly configure it:
CPU scales based on memory
You don't explicitly configure it:
CPU scales based on memory
Memory | vCPUs |
---|---|
128 - 3008 MB | 2 |
3009 - 5307 MB | 3 |
5308 - 7076 MB | 4 |
7077 - 8845 MB | 5 |
8846+ MB | 6 |
export const handler = async(event, context) => {
// ... get data from event
// ... run business logic
// ... return a result
}
export const handler = async(event, context) => {
// ... get data from event
const { url } = event
// ... run business logic
const res = await fetch(url)
console.info(`Status of ${url} : ${res.status}`)
// ... return a result
return res.status
}
How do we make it production ready?
Some example use cases:
# template.yaml
AWSTemplateFormatVersion : '2010-09-09'
Transform:
- AWS::Serverless-2016-10-31
Description: |
A sample Serverless project triggered from S3 CreateObject events
Resources:
ExampleFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs18.x
Handler: index.handler
Events:
S3CreateObject:
Type: S3
Properties:
Bucket: !Ref MyPhotoBucket
Events: s3:ObjectCreated:*
MyPhotoBucket:
Type: AWS::S3::Bucket
(good) Metrics +
Observability Nirvana!
(good) Logs +
(good) Tracing =
npm install \
@aws-lambda-powertools/logger \
@aws-lambda-powertools/metrics \
@aws-lambda-powertools/tracer
export const handler = async(event, context) => {
const { url } = event
const res = await fetch(url)
console.info(`Status of ${url} : ${res.status}`)
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
export const handler = async(event, context) => {
const { url } = event
const res = await fetch(url)
console.info(`Status of ${url} : ${res.status}`)
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
const logger = new Logger({ serviceName: 'httpCheck' })
export const handler = async(event, context) => {
const { url } = event
const res = await fetch(url)
console.info(`Status of ${url} : ${res.status}`)
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
const logger = new Logger({ serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
const res = await fetch(url)
console.info(`Status of ${url} : ${res.status}`)
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
const logger = new Logger({ serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
console.info(`Status of ${url} : ${res.status}`)
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
const logger = new Logger({ serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
return res.status
}
# template.yaml
Type: AWS::Serverless::Function
Properties:
# ..
Environment:
Variables:
LOG_LEVEL: DEBUG
import { Logger } from '@aws-lambda-powertools/logger'
const logger = new Logger({ serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
return res.status
}
import { Logger } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
IaC
SLIC Watch
Deploy to AWS
🤔
🔨🤗
Updated IaC
📈📊🚨
Step 1: deploy the CF Transform Macro
👇
# template.yaml
AWSTemplateFormatVersion : '2010-09-09'
Transform:
- AWS::Serverless-2016-10-31
Description: |
A sample Serverless project triggered from S3 CreateObject events
Resources:
ExampleFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs18.x
Handler: index.handler
Events:
S3CreateObject:
Type: S3
Properties:
Bucket: !Ref MyPhotoBucket
Events: s3:ObjectCreated:*
MyPhotoBucket:
Type: AWS::S3::Bucket
Step 2: Add the SLIC Watch transform
# template.yaml
AWSTemplateFormatVersion : '2010-09-09'
Transform:
- AWS::Serverless-2016-10-31
- SlicWatch-v2
Description: |
A sample Serverless project triggered from S3 CreateObject events
Resources:
ExampleFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs18.x
Handler: index.handler
Events:
S3CreateObject:
Type: S3
Properties:
Bucket: !Ref MyPhotoBucket
Events: s3:ObjectCreated:*
MyPhotoBucket:
Type: AWS::S3::Bucket
Step 2: Add the SLIC Watch transform
# template.yaml
AWSTemplateFormatVersion : '2010-09-09'
Transform:
- AWS::Serverless-2016-10-31
- SlicWatch-v2
Metadata:
slicWatch:
enabled: true
topicArn: !Ref MonitoringTopic
Description: |
A sample Serverless project triggered from S3 CreateObject events
Resources:
ExampleFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs18.x
Handler: index.handler
Events:
S3CreateObject:
Type: S3
Properties:
Bucket: !Ref MyPhotoBucket
Events: s3:ObjectCreated:*
MyPhotoBucket:
Type: AWS::S3::Bucket
Step 3: (optional) add your config
Step 4: deploy!
$ sam deploy
🥳
export const handler = (event, context) => {
// BOILERPLATE!
// E.g. decrypt environment variables with KMS
// deserialize the content of the event
// validate input, authentication, authorization
// REAL BUSINESS LOGIC
const response = doSomethingUsefulWith(event)
// MORE BOILERPLATE
// E.g. validate output
// serialize response
// handle errors
return response
}
export const handler = (event, context) => {
// BOILERPLATE!
// E.g. decrypt environment variables with KMS
// deserialize the content of the event
// validate input, authentication, authorization
// REAL BUSINESS LOGIC
const response = doSomethingUsefulWith(event)
// MORE BOILERPLATE
// E.g. validate output
// serialize response
// handle errors
return response
}
Lots of boilerplate! 🤷♀️
npm install @middy/core
Give it moar love, plz 😍
export const handler = (event, context) => {
// BOILERPLATE!
// E.g. decrypt environment variables with KMS
// deserialize the content of the event
// validate input, authentication, authorization
// REAL BUSINESS LOGIC
const response = doSomethingUsefulWith(event)
// MORE BOILERPLATE
// E.g. validate output
// serialize response
// handle errors
return response
}
import middy from '@middy/core'
export const handler = (event, context) => {
// BOILERPLATE!
// E.g. decrypt environment variables with KMS
// deserialize the content of the event
// validate input, authentication, authorization
// REAL BUSINESS LOGIC
const response = doSomethingUsefulWith(event)
// MORE BOILERPLATE
// E.g. validate output
// serialize response
// handle errors
return response
}
import middy from '@middy/core'
const lambdaHandler = (event, context) => {
// REAL BUSINESS LOGIC
return doSomethingUsefulWith(event)
}
export const handler = (event, context) => {
// BOILERPLATE!
// E.g. decrypt environment variables with KMS
// deserialize the content of the event
// validate input, authentication, authorization
// MORE BOILERPLATE
// E.g. validate output
// serialize response
// handle errors
}
import middy from '@middy/core'
const lambdaHandler = (event, context) => {
// REAL BUSINESS LOGIC
return doSomethingUsefulWith(event)
}
export const handler = middy(lambdaHandler)
.use(/* KMS stuff */)
.use(/* input deserializer */)
.use(/* validation */)
.use(/* auth */)
.use(/* output serialization */)
.use(/* error handling */)
import { Logger } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
import middy from '@middy/core'
import { Logger } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
export const handler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
export const handler = middy(lambdaHandler)
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
logger.debug('Received event', { event })
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
logger.debug('Received event', { event }) // ❌
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
Type: AWS::Serverless::Function
Properties:
# ..
Environment:
Variables:
LOG_LEVEL: DEBUG
POWERTOOLS_LOGGER_LOG_EVENT: "true"
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics()
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
.use(logMetrics(metrics))
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
metrics.publishStoredMetrics() // ❌
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
.use(logMetrics(metrics))
import middy from '@middy/core'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'
const logger = new Logger({ serviceName: 'httpCheck' })
const metrics = new Metrics({ namespace: 'utils', serviceName: 'httpCheck' })
const lambdaHandler = async(event, context) => {
const { url } = event
logger.debug('Checking url', { url })
const res = await fetch(url)
logger.info('Url status', { url, status: res.status })
const successMetric = metrics.singleMetric()
successMetric.addDimension('status', String(res.status))
successMetric.addMetric('successfulRequests', MetricUnits.Count, 1)
metrics.addMetric(`successfulRequests${String(res.status)[0]}xx`, MetricUnits.Count, 1)
return res.status
}
export const handler = middy(lambdaHandler)
.use(injectLambdaContext(logger))
.use(logMetrics(metrics))
And it's very easy to create your own custom middleware!
A step function that can test different configurations of your Lambda
Cover photo by Jonathan Bean on Unsplash
Thanks to Stella Samuel, Eoin Shanaghy, Will Farrell, and Guilherme Dalla Rosa for the awesome suggestions!
Grab these slides!
By Luciano Mammino
A few tips that I learned along the way on how to build production-grade lambdas using AWS: testing, logging, metrics, tracing, infrastructure as code, code reuse, frameworks, and more! Writing Lambdas is quite easy, at the end of the day it is just a function, right?! But writing GOOD production-grade lambdas, well that is an entirely another story. In this talk, I will share some of the tips and tricks that I learned in building Lambda functions in Node.js during the last 6 years. We will talk about code organization and code reuse, logging, metrics, tracing, infrastructure as code, and more.
Cloud developer, entrepreneur, fighter, butterfly maker! #nodejs #javascript - Author of https://www.nodejsdesignpatterns.com , Founder of https://fullstackbulletin.com