SlideShare una empresa de Scribd logo
1 de 57
from
Big Band Web App
to
Serverless
Bebop
@AnjanaVakil JazzCon.Tech 2018
Hello!
I’m @AnjanaVakil
Recurse Center Non-Graduate
Mozilla TechSpeaker & Outreachy Alumna
Engineering Learning & Development Lead, Mapbox
location data platform for developers
maps, search, navigation
web, iOS, Android, Unity...
@AnjanaVakil JazzCon.Tech 2018
@AnjanaVakil JazzCon.Tech 2018
we use to
◍ get user stats
◍ monitor/test unpacker
uploads
◍ ask yoda who’s on call
◍ see who’s out tmrw
◍ pick a random teammate
Place your screenshot here
@AnjanaVakil JazzCon.Tech 2018
user-
limits
out
unpackeryoda
stats
Express
slack i/o
auth
our slack-commands app
node
@AnjanaVakil JazzCon.Tech 2018
codebase
slack-commands/
├─ readme.md
├─ cloudformation/ #app & cmd config
│ └─ slack-commands.template.js
├─ index.js #express app
├─ commands/
│ ├─ out.js
│ ├─ stats.js
│ └─ ...
└─ test/
├─ index.test.js
├─ out.test.js
├─ stats.test.js
└─ ...
@AnjanaVakil JazzCon.Tech 2018
All commands in a single app: Downsides
Security
◍ Permissions?
Secrets?
◍ Least privilege
Maintenance
◍ Many different
teams involved
◍ Ownership?
Support?
◍ Code gumbo
Cost
◍ Always running
◍ No per-command
breakdown
@AnjanaVakil JazzCon.Tech 2018
enough
about computers
let’s talk about jazz
@AnjanaVakil JazzCon.Tech 2018
“
While swing music tended to feature
orchestrated big band arrangements,
bebop music highlighted improvisation.
@AnjanaVakil JazzCon.Tech 2018
wikipedia
Big Band
Glenn Miller Orchestra, c. 1940
Big Band
out unpacker
status
yoda
Express
slack i/o
auth
user-
limits
@AnjanaVakil JazzCon.Tech 2018
“I kept thinking there's bound to be something
else. I could hear it sometimes. I couldn't play it....
I found that by using the higher intervals of a
chord as a melody line and backing them with
appropriately related changes, I could play the
thing I'd been hearing. It came alive.
- Charlie Parker
@AnjanaVakil JazzCon.Tech 2018
wikipedia
Bebop
Tommy Potter, Charlie Parker, Max Roach, Miles Davis, & Duke Jordan, NYC c. 1945
“As bebop was not intended for dancing, it
enabled the musicians to play at faster tempos.
Bebop musicians explored advanced harmonies,
complex syncopation, altered chords, extended
chords, chord substitutions, asymmetrical
phrasing, and intricate melodies.
@AnjanaVakil JazzCon.Tech 2018
wikipedia
Bebop
out
unpacker
status
yoda user-limits
@AnjanaVakil JazzCon.Tech 2018
“there’s bound to be something else”
◍ Assign a single owner/gatekeeper?
◍ Multiple single-command apps?
◍ Separate commands from router app
@AnjanaVakil JazzCon.Tech 2018
“serverless” functions to the rescue
AWS Lambda
@AnjanaVakil JazzCon.Tech 2018
what do you mean “serverless”
Actual Server
You own a computer
You put code on it
You run it constantly
(and you pay constantly)
You keep it healthy
Cloud Server
AWS owns a computer (or 2)
You put code on it
AWS runs it constantly
(and you pay constantly)
You tell AWS how to keep
it healthy
“No” Server
AWS owns a computer
You put code on it
AWS runs it when you ask
(and you pay only then)
AWS keeps it healthy
@AnjanaVakil JazzCon.Tech 2018
◍ Only concern: Input -> Output
◍ No state maintained between calls
◍ Can be side-effecting, though
(e.g. API call, database write)
◍ Limited resources & exec time (5m)
what do you mean “function”
@AnjanaVakil JazzCon.Tech 2018
Lose the server if it’s...
◍ small
◍ short-lived
◍ self-contained
◍ needed occasionally
to lambda or not to lambda
Keep the server if it’s...
◍ heavy
◍ long-running
◍ interdependent
◍ needed constantly
@AnjanaVakil JazzCon.Tech 2018
HTTP API
endpoint
AWS
load
balancerEC2s on ECS
JS
JSJS
old architecture
@AnjanaVakil JazzCon.Tech 2018
HTTP API
endpoint
router
new architecture
stats
out
unpacker
yoda
@AnjanaVakil JazzCon.Tech 2018
old
codebase
slack-commands/
├─ readme.md
├─ cloudformation/ #app & cmd config
│ └─ slack-commands.template.js
├─ index.js #express app code
├─ commands/ #cmd code
│ ├─ out.js
│ ├─ stats.js
│ └─ ...
└─ test/ #app & cmd tests
├─ index.test.js
├─ out.test.js
├─ stats.test.js
└─ ...
@AnjanaVakil JazzCon.Tech 2018
new
codebase
slack-commands/
├─ readme.md
├─ cloudformation/ #app config
│ └─ slack-commands.template.js
├─ index.js #express app code
├─ commander.js #invoke lambdas
└─ test/
├─ commander.test.js
└─ index.test.js
slack-command-{cmd}/
├ readme.md
├ cloudformation/ #cmd config
│ └ slack-command-{cmd}.template.js
├ index.js #cmd code
└ test/
└ index.test.js@AnjanaVakil JazzCon.Tech 2018
what does a
function
look like?
@AnjanaVakil JazzCon.Tech 2018
Place your screenshot here
user stats commmand
@AnjanaVakil JazzCon.Tech 2018
module.exports.command = (event, context, callback) => {
const { ApiCoreUrl, MapboxToken } = process.env;
const user = event.args[0];
const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d
const to = new Date(event.args[2] || (+new Date));
if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date'));
const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken);
request(requrl, (err, res, body) => {
if (err||res.statusCode !== 200) return callback(err||res.statusCode);
try { const data = JSON.parse(body); }
catch(err) { return callback(err); }
return callback(null, formatStatsMessage(user, data));
});
}
@AnjanaVakil JazzCon.Tech 2018
module.exports.command = (event, context, callback) => {
const { ApiCoreUrl, MapboxToken } = process.env;
const user = event.args[0];
const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d
const to = new Date(event.args[2] || (+new Date));
if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date'));
const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken);
request(requrl, (err, res, body) => {
if (err||res.statusCode !== 200) return callback(err||res.statusCode);
try { const data = JSON.parse(body); }
catch(err) { return callback(err); }
return callback(null, formatStatsMessage(user, data));
});
}
handler function
(we tell Lambda its name)
@AnjanaVakil JazzCon.Tech 2018
module.exports.command = (event, context, callback) => {
const { ApiCoreUrl, MapboxToken } = process.env;
const user = event.args[0];
const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d
const to = new Date(event.args[2] || (+new Date));
if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date'));
const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken);
request(requrl, (err, res, body) => {
if (err||res.statusCode !== 200) return callback(err||res.statusCode);
try { const data = JSON.parse(body); }
catch(err) { return callback(err); }
return callback(null, formatStatsMessage(user, data));
});
}
execution environment
we can configure
@AnjanaVakil JazzCon.Tech 2018
module.exports.command = (event, context, callback) => {
const { ApiCoreUrl, MapboxToken } = process.env;
const user = event.args[0];
const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d
const to = new Date(event.args[2] || (+new Date));
if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date'));
const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken);
request(requrl, (err, res, body) => {
if (err||res.statusCode !== 200) return callback(err||res.statusCode);
try { const data = JSON.parse(body); }
catch(err) { return callback(err); }
return callback(null, formatStatsMessage(user, data));
});
}
input { args: [ “vakila”, “1/1”, “3/22”] }
@AnjanaVakil JazzCon.Tech 2018
module.exports.command = (event, context, callback) => {
const { ApiCoreUrl, MapboxToken } = process.env;
const user = event.args[0];
const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d
const to = new Date(event.args[2] || (+new Date));
if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date'));
const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken);
request(requrl, (err, res, body) => {
if (err||res.statusCode !== 200) return callback(err||res.statusCode);
try { const data = JSON.parse(body); }
catch(err) { return callback(err); }
return callback(null, formatStatsMessage(user, data));
});
}
aws runtime info
(e.g. time remaining - ignored here)
@AnjanaVakil JazzCon.Tech 2018
module.exports.command = (event, context, callback) => {
const { ApiCoreUrl, MapboxToken } = process.env;
const user = event.args[0];
const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d
const to = new Date(event.args[2] || (+new Date));
if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date'));
const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken);
request(requrl, (err, res, body) => {
if (err||res.statusCode !== 200) return callback(err||res.statusCode);
try { const data = JSON.parse(body); }
catch(err) { return callback(err); }
return callback(null, formatStatsMessage(user, data));
});
}
“ok, I’m done” function
(AWS passes this when executing)
error data
@AnjanaVakil JazzCon.Tech 2018
we wrote a function!
yay
@AnjanaVakil JazzCon.Tech 2018
do we get it up there?
how
@AnjanaVakil JazzCon.Tech 2018
Cloud::Formation templates
◍ JSON template - “just code”
◍ define your AWS stack components
◍ upload -> AWS builds your stack
@AnjanaVakil JazzCon.Tech 2018
Cloud::Formation templates
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "slack-command-stats",
"Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...}
"Resources": {
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {...}
},
"CommandRole": {
"Type": "AWS::IAM::Role",
"Properties": {...}
}
},
"Outputs": { ... }
}
@AnjanaVakil JazzCon.Tech 2018
Cloud::Formation templates
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "slack-command-stats",
"Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...}
"Resources": {
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {...}
},
"CommandRole": {
"Type": "AWS::IAM::Role",
"Properties": {...}
}
},
"Outputs": { ... }
}
stack
input
params
@AnjanaVakil JazzCon.Tech 2018
Cloud::Formation templates
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "slack-command-stats",
"Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...}
"Resources": {
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {...}
},
"CommandRole": {
"Type": "AWS::IAM::Role",
"Properties": {...}
}
},
"Outputs": { ... }
}
aws
permissions
for function
@AnjanaVakil JazzCon.Tech 2018
Cloud::Formation templates
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "slack-command-stats",
"Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...}
"Resources": {
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {...}
},
"CommandRole": {
"Type": "AWS::IAM::Role",
"Properties": {...}
}
},
"Outputs": { ... }
}
actual
lambda
function
the good stuff
@AnjanaVakil JazzCon.Tech 2018
Cloud::Formation templates
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "slack-command-stats-production",
"Code": { "S3Bucket": {...}, "S3Key": {...} },
"Handler": "index.command",
"Environment": { "Variables": {
"ApiCoreUrl": { "Ref": "ApiCoreUrl" },
"MapboxToken": { "Ref": "MapboxToken" } } },
"Role": { "Fn::GetAtt": ["CommandRole","Arn"] },
"Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60,
"Tags": [ { "Key": "Team", "Value": "EngOps"} ]
}
}
@AnjanaVakil JazzCon.Tech 2018
Cloud::Formation templates
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "slack-command-stats-production",
"Code": { "S3Bucket": {...}, "S3Key": {...} },
"Handler": "index.command",
"Environment": { "Variables": {
"ApiCoreUrl": { "Ref": "ApiCoreUrl" },
"MapboxToken": { "Ref": "MapboxToken" } } },
"Role": { "Fn::GetAtt": ["CommandRole","Arn"] },
"Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60,
"Tags": [ { "Key": "Team", "Value": "EngOps"} ]
}
}
@AnjanaVakil JazzCon.Tech 2018
function
name
helps find it later
Cloud::Formation templates
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "slack-command-stats-production",
"Code": { "S3Bucket": {...}, "S3Key": {...} },
"Handler": "index.command",
"Environment": { "Variables": {
"ApiCoreUrl": { "Ref": "ApiCoreUrl" },
"MapboxToken": { "Ref": "MapboxToken" } } },
"Role": { "Fn::GetAtt": ["CommandRole","Arn"] },
"Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60,
"Tags": [ { "Key": "Team", "Value": "EngOps"} ]
}
}
@AnjanaVakil JazzCon.Tech 2018
code to run
the good stuff
Cloud::Formation templates
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "slack-command-stats-production",
"Code": { "S3Bucket": {...}, "S3Key": {...} },
"Handler": "index.command",
"Environment": { "Variables": {
"ApiCoreUrl": { "Ref": "ApiCoreUrl" },
"MapboxToken": { "Ref": "MapboxToken" } } },
"Role": { "Fn::GetAtt": ["CommandRole","Arn"] },
"Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60,
"Tags": [ { "Key": "Team", "Value": "EngOps"} ]
}
}
@AnjanaVakil JazzCon.Tech 2018
execution
environment
can pass in params
Cloud::Formation templates
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "slack-command-stats-production",
"Code": { "S3Bucket": {...}, "S3Key": {...} },
"Handler": "index.command",
"Environment": { "Variables": {
"ApiCoreUrl": { "Ref": "ApiCoreUrl" },
"MapboxToken": { "Ref": "MapboxToken" } } },
"Role": { "Fn::GetAtt": ["CommandRole","Arn"] },
"Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60,
"Tags": [ { "Key": "Team", "Value": "EngOps"} ]
}
}
@AnjanaVakil JazzCon.Tech 2018
permissions
from earlier
Cloud::Formation templates
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "slack-command-stats-production",
"Code": { "S3Bucket": {...}, "S3Key": {...} },
"Handler": "index.command",
"Environment": { "Variables": {
"ApiCoreUrl": { "Ref": "ApiCoreUrl" },
"MapboxToken": { "Ref": "MapboxToken" } } },
"Role": { "Fn::GetAtt": ["CommandRole","Arn"] },
"Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60,
"Tags": [ { "Key": "Team", "Value": "EngOps"} ]
}
}
@AnjanaVakil JazzCon.Tech 2018
what to run it on
totally not a server
Cloud::Formation templates
"Command": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "slack-command-stats-production",
"Code": { "S3Bucket": {...}, "S3Key": {...} },
"Handler": "index.command",
"Environment": { "Variables": {
"ApiCoreUrl": { "Ref": "ApiCoreUrl" },
"MapboxToken": { "Ref": "MapboxToken" } } },
"Role": { "Fn::GetAtt": ["CommandRole","Arn"] },
"Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60,
"Tags": [ { "Key": "Team", "Value": "EngOps"} ]
}
}
@AnjanaVakil JazzCon.Tech 2018
arbitrary tags
e.g. who owns this?
Mapbox open-source AWS
helpers
github.com/mapbox/
Command-line tools
lambda-cfn create & deploy Node Lambda functions
cfn-config configure/start/update CFN stacks
JS libraries
cloudfriend easily assemble CFN templates in JS
decrypt-kms-env use secret environment vars
@AnjanaVakil JazzCon.Tech 2018
we deployed a function!
yay
@AnjanaVakil JazzCon.Tech 2018
do we call it?
how
@AnjanaVakil JazzCon.Tech 2018
testing in the AWS console (manually)
@AnjanaVakil JazzCon.Tech 2018
in Node with AWS SDK
const AWS = require('aws-sdk');
const runCommand = (req, res, next) => {
const [commandName, ...args] = = req.slackText;
const params = {
FunctionName: `slack-command-${commandName}-production`, // our convention
Payload: JSON.stringify({ args: args }), // the `event` Lambda receives
};
const lambda = new AWS.Lambda({ region: 'us-east-1' });
lambda.invoke(params).promise()
.catch((err) => err.message) // pass on error message as response data
.then((data) => res.json(formatForSlack(data)));
};
@AnjanaVakil JazzCon.Tech 2018
why
did we do all that?
@AnjanaVakil JazzCon.Tech 2018
Before (single app)
◍ Many secrets in one
stack
◍ Updating your code
updates whole stack
◍ No fine-grained cost
analysis
Refactoring to Lambda: Benefits
After (multiple Lambdas)
◍ Each stack only knows
its own secrets
◍ Updating your code
leaves others untouched
◍ Each stack/fn can be
tagged & cost-monitored
@AnjanaVakil JazzCon.Tech 2018
HTTP API
endpoint
router
next steps
stats
out
unpacker
yoda
@AnjanaVakil JazzCon.Tech 2018
HTTP API
endpoint
next steps
stats
out
unpacker
yoda
@AnjanaVakil JazzCon.Tech 2018
router
Merci!
@AnjanaVakil
anjana@mapbox.com
✌ Team Mapbox
Young Hahn, Emily McAfee,
Kelly Young, Jake Pruitt, Andrew Evans
JazzCon.Tech Organizers
Images from Wikimedia
Template by SlidesCarnival.com

Más contenido relacionado

La actualidad más candente

Business Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache AirflowBusiness Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache AirflowRomain Dorgueil
 
Scaling up data science applications
Scaling up data science applicationsScaling up data science applications
Scaling up data science applicationsKexin Xie
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Ignacio Martín
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on AndroidTomáš Kypta
 
Understanding reactive programming with microsoft reactive extensions
Understanding reactive programming  with microsoft reactive extensionsUnderstanding reactive programming  with microsoft reactive extensions
Understanding reactive programming with microsoft reactive extensionsOleksandr Zhevzhyk
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every dayVadym Khondar
 
Scala.js: Next generation front end development in Scala
Scala.js:  Next generation front end development in ScalaScala.js:  Next generation front end development in Scala
Scala.js: Next generation front end development in ScalaOtto Chrons
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga beginsDaniel Franz
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React AlicanteIgnacio Martín
 
A dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenarioA dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenarioGioia Ballin
 
Spark Your Legacy (Spark Summit 2016)
Spark Your Legacy (Spark Summit 2016)Spark Your Legacy (Spark Summit 2016)
Spark Your Legacy (Spark Summit 2016)Tzach Zohar
 
Using Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsUsing Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsGlobalLogic Ukraine
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creatorsGeorge Bukhanov
 
Reactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz KhambatiReactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz KhambatiAziz Khambati
 
Swift Ready for Production?
Swift Ready for Production?Swift Ready for Production?
Swift Ready for Production?Crispy Mountain
 
Using akka streams to access s3 objects
Using akka streams to access s3 objectsUsing akka streams to access s3 objects
Using akka streams to access s3 objectsMikhail Girkin
 
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)DataStax Academy
 
Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...
Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...
Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...InfluxData
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Ben Lesh
 

La actualidad más candente (20)

Business Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache AirflowBusiness Dashboards using Bonobo ETL, Grafana and Apache Airflow
Business Dashboards using Bonobo ETL, Grafana and Apache Airflow
 
Scaling up data science applications
Scaling up data science applicationsScaling up data science applications
Scaling up data science applications
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
 
Understanding reactive programming with microsoft reactive extensions
Understanding reactive programming  with microsoft reactive extensionsUnderstanding reactive programming  with microsoft reactive extensions
Understanding reactive programming with microsoft reactive extensions
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
 
Scala.js: Next generation front end development in Scala
Scala.js:  Next generation front end development in ScalaScala.js:  Next generation front end development in Scala
Scala.js: Next generation front end development in Scala
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
A dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenarioA dive into akka streams: from the basics to a real-world scenario
A dive into akka streams: from the basics to a real-world scenario
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
 
Spark Your Legacy (Spark Summit 2016)
Spark Your Legacy (Spark Summit 2016)Spark Your Legacy (Spark Summit 2016)
Spark Your Legacy (Spark Summit 2016)
 
Using Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsUsing Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side Effects
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creators
 
Reactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz KhambatiReactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz Khambati
 
Swift Ready for Production?
Swift Ready for Production?Swift Ready for Production?
Swift Ready for Production?
 
Using akka streams to access s3 objects
Using akka streams to access s3 objectsUsing akka streams to access s3 objects
Using akka streams to access s3 objects
 
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
 
Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...
Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...
Barbara Nelson [InfluxData] | How Can I Put That Dashboard in My App? | Influ...
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
 

Similar a From Big Band Web App to Serverless Bebop

RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]Igor Lozynskyi
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJSKyung Yeol Kim
 
MongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-esMongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-esMongoDB
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the mastersAra Pehlivanian
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013Laurent_VB
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemSages
 
Wprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache HadoopWprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache HadoopSages
 
用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構Bo-Yi Wu
 
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry PiMonitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry PiInfluxData
 
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...Ben Teese
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0Tobias Meixner
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJSstefanmayer13
 
LSFMM 2019 BPF Observability
LSFMM 2019 BPF ObservabilityLSFMM 2019 BPF Observability
LSFMM 2019 BPF ObservabilityBrendan Gregg
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jscacois
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveJeff Smith
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 

Similar a From Big Band Web App to Serverless Bebop (20)

Lambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter LawreyLambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter Lawrey
 
RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJS
 
MongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-esMongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-es
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the masters
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
 
Wprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache HadoopWprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache Hadoop
 
用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構
 
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry PiMonitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
 
Analytics with Spark
Analytics with SparkAnalytics with Spark
Analytics with Spark
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJS
 
LSFMM 2019 BPF Observability
LSFMM 2019 BPF ObservabilityLSFMM 2019 BPF Observability
LSFMM 2019 BPF Observability
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more Reactive
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 

Más de JSFestUA

JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in productionJS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in productionJSFestUA
 
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript PerformanceJS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript PerformanceJSFestUA
 
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"JSFestUA
 
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...JSFestUA
 
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...JSFestUA
 
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...JSFestUA
 
JS Fest 2019/Autumn. Александр Товмач. JAMstack
JS Fest 2019/Autumn. Александр Товмач. JAMstackJS Fest 2019/Autumn. Александр Товмач. JAMstack
JS Fest 2019/Autumn. Александр Товмач. JAMstackJSFestUA
 
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...JSFestUA
 
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...JSFestUA
 
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developersJS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developersJSFestUA
 
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...JSFestUA
 
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?JSFestUA
 
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the ScaleJS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the ScaleJSFestUA
 
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratchJS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratchJSFestUA
 
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотятJS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотятJSFestUA
 
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for RustJS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for RustJSFestUA
 
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...JSFestUA
 
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проектіJS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проектіJSFestUA
 
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядроJS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядроJSFestUA
 
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...JSFestUA
 

Más de JSFestUA (20)

JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in productionJS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
 
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript PerformanceJS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
 
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
 
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
 
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
 
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
 
JS Fest 2019/Autumn. Александр Товмач. JAMstack
JS Fest 2019/Autumn. Александр Товмач. JAMstackJS Fest 2019/Autumn. Александр Товмач. JAMstack
JS Fest 2019/Autumn. Александр Товмач. JAMstack
 
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
 
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
 
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developersJS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
 
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
 
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
 
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the ScaleJS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
 
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratchJS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
 
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотятJS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
 
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for RustJS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
 
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
 
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проектіJS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
 
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядроJS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
 
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
 

Último

Judging the Relevance and worth of ideas part 2.pptx
Judging the Relevance  and worth of ideas part 2.pptxJudging the Relevance  and worth of ideas part 2.pptx
Judging the Relevance and worth of ideas part 2.pptxSherlyMaeNeri
 
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17Celine George
 
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTSGRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTSJoshuaGantuangco2
 
Q4 English4 Week3 PPT Melcnmg-based.pptx
Q4 English4 Week3 PPT Melcnmg-based.pptxQ4 English4 Week3 PPT Melcnmg-based.pptx
Q4 English4 Week3 PPT Melcnmg-based.pptxnelietumpap1
 
Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17Celine George
 
ENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomnelietumpap1
 
Earth Day Presentation wow hello nice great
Earth Day Presentation wow hello nice greatEarth Day Presentation wow hello nice great
Earth Day Presentation wow hello nice greatYousafMalik24
 
Science 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptxScience 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptxMaryGraceBautista27
 
INTRODUCTION TO CATHOLIC CHRISTOLOGY.pptx
INTRODUCTION TO CATHOLIC CHRISTOLOGY.pptxINTRODUCTION TO CATHOLIC CHRISTOLOGY.pptx
INTRODUCTION TO CATHOLIC CHRISTOLOGY.pptxHumphrey A Beña
 
Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17Celine George
 
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdfInclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdfTechSoup
 
USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...
USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...
USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...Postal Advocate Inc.
 
ACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdfACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdfSpandanaRallapalli
 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Mark Reed
 
Roles & Responsibilities in Pharmacovigilance
Roles & Responsibilities in PharmacovigilanceRoles & Responsibilities in Pharmacovigilance
Roles & Responsibilities in PharmacovigilanceSamikshaHamane
 
Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...Jisc
 
What is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERPWhat is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERPCeline George
 
ECONOMIC CONTEXT - LONG FORM TV DRAMA - PPT
ECONOMIC CONTEXT - LONG FORM TV DRAMA - PPTECONOMIC CONTEXT - LONG FORM TV DRAMA - PPT
ECONOMIC CONTEXT - LONG FORM TV DRAMA - PPTiammrhaywood
 

Último (20)

Judging the Relevance and worth of ideas part 2.pptx
Judging the Relevance  and worth of ideas part 2.pptxJudging the Relevance  and worth of ideas part 2.pptx
Judging the Relevance and worth of ideas part 2.pptx
 
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
 
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTSGRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
 
Q4 English4 Week3 PPT Melcnmg-based.pptx
Q4 English4 Week3 PPT Melcnmg-based.pptxQ4 English4 Week3 PPT Melcnmg-based.pptx
Q4 English4 Week3 PPT Melcnmg-based.pptx
 
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptxYOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
 
Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17
 
ENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choom
 
Earth Day Presentation wow hello nice great
Earth Day Presentation wow hello nice greatEarth Day Presentation wow hello nice great
Earth Day Presentation wow hello nice great
 
Science 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptxScience 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptx
 
INTRODUCTION TO CATHOLIC CHRISTOLOGY.pptx
INTRODUCTION TO CATHOLIC CHRISTOLOGY.pptxINTRODUCTION TO CATHOLIC CHRISTOLOGY.pptx
INTRODUCTION TO CATHOLIC CHRISTOLOGY.pptx
 
Raw materials used in Herbal Cosmetics.pptx
Raw materials used in Herbal Cosmetics.pptxRaw materials used in Herbal Cosmetics.pptx
Raw materials used in Herbal Cosmetics.pptx
 
Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17
 
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdfInclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
 
USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...
USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...
USPS® Forced Meter Migration - How to Know if Your Postage Meter Will Soon be...
 
ACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdfACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdf
 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)
 
Roles & Responsibilities in Pharmacovigilance
Roles & Responsibilities in PharmacovigilanceRoles & Responsibilities in Pharmacovigilance
Roles & Responsibilities in Pharmacovigilance
 
Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...
 
What is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERPWhat is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERP
 
ECONOMIC CONTEXT - LONG FORM TV DRAMA - PPT
ECONOMIC CONTEXT - LONG FORM TV DRAMA - PPTECONOMIC CONTEXT - LONG FORM TV DRAMA - PPT
ECONOMIC CONTEXT - LONG FORM TV DRAMA - PPT
 

From Big Band Web App to Serverless Bebop

  • 1. from Big Band Web App to Serverless Bebop @AnjanaVakil JazzCon.Tech 2018
  • 2. Hello! I’m @AnjanaVakil Recurse Center Non-Graduate Mozilla TechSpeaker & Outreachy Alumna Engineering Learning & Development Lead, Mapbox
  • 3. location data platform for developers maps, search, navigation web, iOS, Android, Unity... @AnjanaVakil JazzCon.Tech 2018
  • 5. we use to ◍ get user stats ◍ monitor/test unpacker uploads ◍ ask yoda who’s on call ◍ see who’s out tmrw ◍ pick a random teammate Place your screenshot here @AnjanaVakil JazzCon.Tech 2018
  • 7. codebase slack-commands/ ├─ readme.md ├─ cloudformation/ #app & cmd config │ └─ slack-commands.template.js ├─ index.js #express app ├─ commands/ │ ├─ out.js │ ├─ stats.js │ └─ ... └─ test/ ├─ index.test.js ├─ out.test.js ├─ stats.test.js └─ ... @AnjanaVakil JazzCon.Tech 2018
  • 8. All commands in a single app: Downsides Security ◍ Permissions? Secrets? ◍ Least privilege Maintenance ◍ Many different teams involved ◍ Ownership? Support? ◍ Code gumbo Cost ◍ Always running ◍ No per-command breakdown @AnjanaVakil JazzCon.Tech 2018
  • 9. enough about computers let’s talk about jazz @AnjanaVakil JazzCon.Tech 2018
  • 10. “ While swing music tended to feature orchestrated big band arrangements, bebop music highlighted improvisation. @AnjanaVakil JazzCon.Tech 2018 wikipedia
  • 11. Big Band Glenn Miller Orchestra, c. 1940
  • 12. Big Band out unpacker status yoda Express slack i/o auth user- limits @AnjanaVakil JazzCon.Tech 2018
  • 13. “I kept thinking there's bound to be something else. I could hear it sometimes. I couldn't play it.... I found that by using the higher intervals of a chord as a melody line and backing them with appropriately related changes, I could play the thing I'd been hearing. It came alive. - Charlie Parker @AnjanaVakil JazzCon.Tech 2018 wikipedia
  • 14. Bebop Tommy Potter, Charlie Parker, Max Roach, Miles Davis, & Duke Jordan, NYC c. 1945
  • 15. “As bebop was not intended for dancing, it enabled the musicians to play at faster tempos. Bebop musicians explored advanced harmonies, complex syncopation, altered chords, extended chords, chord substitutions, asymmetrical phrasing, and intricate melodies. @AnjanaVakil JazzCon.Tech 2018 wikipedia
  • 17. “there’s bound to be something else” ◍ Assign a single owner/gatekeeper? ◍ Multiple single-command apps? ◍ Separate commands from router app @AnjanaVakil JazzCon.Tech 2018
  • 18. “serverless” functions to the rescue AWS Lambda @AnjanaVakil JazzCon.Tech 2018
  • 19. what do you mean “serverless” Actual Server You own a computer You put code on it You run it constantly (and you pay constantly) You keep it healthy Cloud Server AWS owns a computer (or 2) You put code on it AWS runs it constantly (and you pay constantly) You tell AWS how to keep it healthy “No” Server AWS owns a computer You put code on it AWS runs it when you ask (and you pay only then) AWS keeps it healthy @AnjanaVakil JazzCon.Tech 2018
  • 20. ◍ Only concern: Input -> Output ◍ No state maintained between calls ◍ Can be side-effecting, though (e.g. API call, database write) ◍ Limited resources & exec time (5m) what do you mean “function” @AnjanaVakil JazzCon.Tech 2018
  • 21. Lose the server if it’s... ◍ small ◍ short-lived ◍ self-contained ◍ needed occasionally to lambda or not to lambda Keep the server if it’s... ◍ heavy ◍ long-running ◍ interdependent ◍ needed constantly @AnjanaVakil JazzCon.Tech 2018
  • 22. HTTP API endpoint AWS load balancerEC2s on ECS JS JSJS old architecture @AnjanaVakil JazzCon.Tech 2018
  • 24. old codebase slack-commands/ ├─ readme.md ├─ cloudformation/ #app & cmd config │ └─ slack-commands.template.js ├─ index.js #express app code ├─ commands/ #cmd code │ ├─ out.js │ ├─ stats.js │ └─ ... └─ test/ #app & cmd tests ├─ index.test.js ├─ out.test.js ├─ stats.test.js └─ ... @AnjanaVakil JazzCon.Tech 2018
  • 25. new codebase slack-commands/ ├─ readme.md ├─ cloudformation/ #app config │ └─ slack-commands.template.js ├─ index.js #express app code ├─ commander.js #invoke lambdas └─ test/ ├─ commander.test.js └─ index.test.js slack-command-{cmd}/ ├ readme.md ├ cloudformation/ #cmd config │ └ slack-command-{cmd}.template.js ├ index.js #cmd code └ test/ └ index.test.js@AnjanaVakil JazzCon.Tech 2018
  • 26. what does a function look like? @AnjanaVakil JazzCon.Tech 2018
  • 27. Place your screenshot here user stats commmand @AnjanaVakil JazzCon.Tech 2018
  • 28. module.exports.command = (event, context, callback) => { const { ApiCoreUrl, MapboxToken } = process.env; const user = event.args[0]; const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d const to = new Date(event.args[2] || (+new Date)); if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date')); const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken); request(requrl, (err, res, body) => { if (err||res.statusCode !== 200) return callback(err||res.statusCode); try { const data = JSON.parse(body); } catch(err) { return callback(err); } return callback(null, formatStatsMessage(user, data)); }); } @AnjanaVakil JazzCon.Tech 2018
  • 29. module.exports.command = (event, context, callback) => { const { ApiCoreUrl, MapboxToken } = process.env; const user = event.args[0]; const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d const to = new Date(event.args[2] || (+new Date)); if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date')); const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken); request(requrl, (err, res, body) => { if (err||res.statusCode !== 200) return callback(err||res.statusCode); try { const data = JSON.parse(body); } catch(err) { return callback(err); } return callback(null, formatStatsMessage(user, data)); }); } handler function (we tell Lambda its name) @AnjanaVakil JazzCon.Tech 2018
  • 30. module.exports.command = (event, context, callback) => { const { ApiCoreUrl, MapboxToken } = process.env; const user = event.args[0]; const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d const to = new Date(event.args[2] || (+new Date)); if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date')); const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken); request(requrl, (err, res, body) => { if (err||res.statusCode !== 200) return callback(err||res.statusCode); try { const data = JSON.parse(body); } catch(err) { return callback(err); } return callback(null, formatStatsMessage(user, data)); }); } execution environment we can configure @AnjanaVakil JazzCon.Tech 2018
  • 31. module.exports.command = (event, context, callback) => { const { ApiCoreUrl, MapboxToken } = process.env; const user = event.args[0]; const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d const to = new Date(event.args[2] || (+new Date)); if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date')); const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken); request(requrl, (err, res, body) => { if (err||res.statusCode !== 200) return callback(err||res.statusCode); try { const data = JSON.parse(body); } catch(err) { return callback(err); } return callback(null, formatStatsMessage(user, data)); }); } input { args: [ “vakila”, “1/1”, “3/22”] } @AnjanaVakil JazzCon.Tech 2018
  • 32. module.exports.command = (event, context, callback) => { const { ApiCoreUrl, MapboxToken } = process.env; const user = event.args[0]; const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d const to = new Date(event.args[2] || (+new Date)); if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date')); const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken); request(requrl, (err, res, body) => { if (err||res.statusCode !== 200) return callback(err||res.statusCode); try { const data = JSON.parse(body); } catch(err) { return callback(err); } return callback(null, formatStatsMessage(user, data)); }); } aws runtime info (e.g. time remaining - ignored here) @AnjanaVakil JazzCon.Tech 2018
  • 33. module.exports.command = (event, context, callback) => { const { ApiCoreUrl, MapboxToken } = process.env; const user = event.args[0]; const from = new Date(event.args[1] || (+new Date - 864e5*30)); // 30d const to = new Date(event.args[2] || (+new Date)); if (isNaN(from)||isNaN(to)) return callback(new Error('invalid date')); const requrl = getStatsUrl(user, from, to, ApiCoreUrl, MapboxToken); request(requrl, (err, res, body) => { if (err||res.statusCode !== 200) return callback(err||res.statusCode); try { const data = JSON.parse(body); } catch(err) { return callback(err); } return callback(null, formatStatsMessage(user, data)); }); } “ok, I’m done” function (AWS passes this when executing) error data @AnjanaVakil JazzCon.Tech 2018
  • 34. we wrote a function! yay @AnjanaVakil JazzCon.Tech 2018
  • 35. do we get it up there? how @AnjanaVakil JazzCon.Tech 2018
  • 36. Cloud::Formation templates ◍ JSON template - “just code” ◍ define your AWS stack components ◍ upload -> AWS builds your stack @AnjanaVakil JazzCon.Tech 2018
  • 37. Cloud::Formation templates { "AWSTemplateFormatVersion": "2010-09-09", "Description": "slack-command-stats", "Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...} "Resources": { "Command": { "Type": "AWS::Lambda::Function", "Properties": {...} }, "CommandRole": { "Type": "AWS::IAM::Role", "Properties": {...} } }, "Outputs": { ... } } @AnjanaVakil JazzCon.Tech 2018
  • 38. Cloud::Formation templates { "AWSTemplateFormatVersion": "2010-09-09", "Description": "slack-command-stats", "Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...} "Resources": { "Command": { "Type": "AWS::Lambda::Function", "Properties": {...} }, "CommandRole": { "Type": "AWS::IAM::Role", "Properties": {...} } }, "Outputs": { ... } } stack input params @AnjanaVakil JazzCon.Tech 2018
  • 39. Cloud::Formation templates { "AWSTemplateFormatVersion": "2010-09-09", "Description": "slack-command-stats", "Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...} "Resources": { "Command": { "Type": "AWS::Lambda::Function", "Properties": {...} }, "CommandRole": { "Type": "AWS::IAM::Role", "Properties": {...} } }, "Outputs": { ... } } aws permissions for function @AnjanaVakil JazzCon.Tech 2018
  • 40. Cloud::Formation templates { "AWSTemplateFormatVersion": "2010-09-09", "Description": "slack-command-stats", "Parameters": { "ApiCoreUrl": {...}, "MapboxToken": {...} "Resources": { "Command": { "Type": "AWS::Lambda::Function", "Properties": {...} }, "CommandRole": { "Type": "AWS::IAM::Role", "Properties": {...} } }, "Outputs": { ... } } actual lambda function the good stuff @AnjanaVakil JazzCon.Tech 2018
  • 41. Cloud::Formation templates "Command": { "Type": "AWS::Lambda::Function", "Properties": { "FunctionName": "slack-command-stats-production", "Code": { "S3Bucket": {...}, "S3Key": {...} }, "Handler": "index.command", "Environment": { "Variables": { "ApiCoreUrl": { "Ref": "ApiCoreUrl" }, "MapboxToken": { "Ref": "MapboxToken" } } }, "Role": { "Fn::GetAtt": ["CommandRole","Arn"] }, "Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60, "Tags": [ { "Key": "Team", "Value": "EngOps"} ] } } @AnjanaVakil JazzCon.Tech 2018
  • 42. Cloud::Formation templates "Command": { "Type": "AWS::Lambda::Function", "Properties": { "FunctionName": "slack-command-stats-production", "Code": { "S3Bucket": {...}, "S3Key": {...} }, "Handler": "index.command", "Environment": { "Variables": { "ApiCoreUrl": { "Ref": "ApiCoreUrl" }, "MapboxToken": { "Ref": "MapboxToken" } } }, "Role": { "Fn::GetAtt": ["CommandRole","Arn"] }, "Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60, "Tags": [ { "Key": "Team", "Value": "EngOps"} ] } } @AnjanaVakil JazzCon.Tech 2018 function name helps find it later
  • 43. Cloud::Formation templates "Command": { "Type": "AWS::Lambda::Function", "Properties": { "FunctionName": "slack-command-stats-production", "Code": { "S3Bucket": {...}, "S3Key": {...} }, "Handler": "index.command", "Environment": { "Variables": { "ApiCoreUrl": { "Ref": "ApiCoreUrl" }, "MapboxToken": { "Ref": "MapboxToken" } } }, "Role": { "Fn::GetAtt": ["CommandRole","Arn"] }, "Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60, "Tags": [ { "Key": "Team", "Value": "EngOps"} ] } } @AnjanaVakil JazzCon.Tech 2018 code to run the good stuff
  • 44. Cloud::Formation templates "Command": { "Type": "AWS::Lambda::Function", "Properties": { "FunctionName": "slack-command-stats-production", "Code": { "S3Bucket": {...}, "S3Key": {...} }, "Handler": "index.command", "Environment": { "Variables": { "ApiCoreUrl": { "Ref": "ApiCoreUrl" }, "MapboxToken": { "Ref": "MapboxToken" } } }, "Role": { "Fn::GetAtt": ["CommandRole","Arn"] }, "Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60, "Tags": [ { "Key": "Team", "Value": "EngOps"} ] } } @AnjanaVakil JazzCon.Tech 2018 execution environment can pass in params
  • 45. Cloud::Formation templates "Command": { "Type": "AWS::Lambda::Function", "Properties": { "FunctionName": "slack-command-stats-production", "Code": { "S3Bucket": {...}, "S3Key": {...} }, "Handler": "index.command", "Environment": { "Variables": { "ApiCoreUrl": { "Ref": "ApiCoreUrl" }, "MapboxToken": { "Ref": "MapboxToken" } } }, "Role": { "Fn::GetAtt": ["CommandRole","Arn"] }, "Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60, "Tags": [ { "Key": "Team", "Value": "EngOps"} ] } } @AnjanaVakil JazzCon.Tech 2018 permissions from earlier
  • 46. Cloud::Formation templates "Command": { "Type": "AWS::Lambda::Function", "Properties": { "FunctionName": "slack-command-stats-production", "Code": { "S3Bucket": {...}, "S3Key": {...} }, "Handler": "index.command", "Environment": { "Variables": { "ApiCoreUrl": { "Ref": "ApiCoreUrl" }, "MapboxToken": { "Ref": "MapboxToken" } } }, "Role": { "Fn::GetAtt": ["CommandRole","Arn"] }, "Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60, "Tags": [ { "Key": "Team", "Value": "EngOps"} ] } } @AnjanaVakil JazzCon.Tech 2018 what to run it on totally not a server
  • 47. Cloud::Formation templates "Command": { "Type": "AWS::Lambda::Function", "Properties": { "FunctionName": "slack-command-stats-production", "Code": { "S3Bucket": {...}, "S3Key": {...} }, "Handler": "index.command", "Environment": { "Variables": { "ApiCoreUrl": { "Ref": "ApiCoreUrl" }, "MapboxToken": { "Ref": "MapboxToken" } } }, "Role": { "Fn::GetAtt": ["CommandRole","Arn"] }, "Runtime": "nodejs4.3", "MemorySize": 128, "Timeout": 60, "Tags": [ { "Key": "Team", "Value": "EngOps"} ] } } @AnjanaVakil JazzCon.Tech 2018 arbitrary tags e.g. who owns this?
  • 48. Mapbox open-source AWS helpers github.com/mapbox/ Command-line tools lambda-cfn create & deploy Node Lambda functions cfn-config configure/start/update CFN stacks JS libraries cloudfriend easily assemble CFN templates in JS decrypt-kms-env use secret environment vars @AnjanaVakil JazzCon.Tech 2018
  • 49. we deployed a function! yay @AnjanaVakil JazzCon.Tech 2018
  • 50. do we call it? how @AnjanaVakil JazzCon.Tech 2018
  • 51. testing in the AWS console (manually) @AnjanaVakil JazzCon.Tech 2018
  • 52. in Node with AWS SDK const AWS = require('aws-sdk'); const runCommand = (req, res, next) => { const [commandName, ...args] = = req.slackText; const params = { FunctionName: `slack-command-${commandName}-production`, // our convention Payload: JSON.stringify({ args: args }), // the `event` Lambda receives }; const lambda = new AWS.Lambda({ region: 'us-east-1' }); lambda.invoke(params).promise() .catch((err) => err.message) // pass on error message as response data .then((data) => res.json(formatForSlack(data))); }; @AnjanaVakil JazzCon.Tech 2018
  • 53. why did we do all that? @AnjanaVakil JazzCon.Tech 2018
  • 54. Before (single app) ◍ Many secrets in one stack ◍ Updating your code updates whole stack ◍ No fine-grained cost analysis Refactoring to Lambda: Benefits After (multiple Lambdas) ◍ Each stack only knows its own secrets ◍ Updating your code leaves others untouched ◍ Each stack/fn can be tagged & cost-monitored @AnjanaVakil JazzCon.Tech 2018
  • 57. Merci! @AnjanaVakil anjana@mapbox.com ✌ Team Mapbox Young Hahn, Emily McAfee, Kelly Young, Jake Pruitt, Andrew Evans JazzCon.Tech Organizers Images from Wikimedia Template by SlidesCarnival.com