SlideShare uma empresa Scribd logo
1 de 76
Baixar para ler offline
BACKGROUND TASKS IN NODE.JS
REDISCONF 2016
@EVANTAHLER
A Survey using Redis
WARNING
MOST OF THE IDEAS IN THIS
PRESENTATION ARE ACTUALLY VERY
BAD IDEAS.
TRY THESE AT ~, NOT ON PRODUCTION
INTRO
HI. I’M EVAN
▸ Director of Technology @ TaskRabbit
▸ Founder of ActionHero.js, node.js
framework
▸ Node-Resque Author
@EVANTAHLER
BLOG.EVANTAHLER.COM
INTRO
WHAT IS NODE.JS
▸ Server-side Framework, uses JS
▸ Async
▸ Fast
WHAT IS REDIS
▸ In-memory database
▸ Structured data
▸ Fast
EVERYTHING IS FASTER IN NODE…
ESPECIALLY THE BAD IDEAS
Me (Evan)
WHAT ARE WE GOING TO TALK ABOUT?
WHAT ARE WE GOING TO TALK ABOUT?
POSSIBLE TASK STRATEGIES:
FOREGROUND (IN-LINE)
PARALLEL (THREAD-ISH)
LOCAL MESSAGES (FORK-ISH)
REMOTE MESSAGES (*MQ-ISH)
REMOTE QUEUE (REDIS + RESQUE)
IMMUTABLE EVENT BUS (KAFKA-ISH)
1) FOREGROUND TASKS
FOREGROUND
THE SERVER
var server = function(req, res){
var start = Date.now();
var responseCode = 200;
var response = {};
sendEmail(req, function(error, email){
response.email = email;
if(error){
console.log(error);
responseCode = 500;
response.error = error;
}
res.writeHead(responseCode, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response, null, 2));
var delta = Date.now() - start;
console.log('Sent an email to ' + email.to + ' in ' + delta + 'ms');
});
};
http.createServer(server).listen(httpPort, httpHost);
Async and non-blocking!
FOREGROUND
SENDING EMAILS
var http = require('http');
var nodemailer = require('nodemailer');
var httpPort = process.env.PORT || 8080;
var httpHost = process.env.HOST || '127.0.0.1';
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: require('./.emailUsername'),
pass: require('./.emailPassword')
}
});
var sendEmail = function(req, callback){
var urlParts = req.url.split('/');
var email = {
from: require('./.emailUsername'),
to: decodeURI(urlParts[1]),
subject: decodeURI(urlParts[2]),
text: decodeURI(urlParts[3]),
};
transporter.sendMail(email, function(error, info){
callback(error, email);
});
};
DEMO TIME
FOREGROUND
STRATEGY SUMMARY
▸ Why it is better in node:
▸ The client still needs to wait for the message to send, but you won’t block any other client’s requests
▸ Avg response time of ~2 seconds from my couch
▸ Why it is still a bad idea:
▸ Slow for the client
▸ Spending “web server” resources on sending email
▸ Error / Timeout to the client for “partial success”
▸ IE: Account created but email not sent
▸ Confusing to the user, dangerous for the DB
2) PARALLEL TASKS
PARALLEL
IMPROVEMENT IDEAS
▸ In any other language this would be called “threading”
▸ But if it were real threading, the client would still have to wait
▸ I guess this might help you catch errors…
▸ *note: do not get into a discussion about threads in node…
▸ Lets get crazy:
▸ Ignore the Callback
PARALLEL
IGNORE THE CALLBACK
var server = function(req, res){
var start = Date.now();
var responseCode = 200;
var response = {};
sendEmail(req);
res.writeHead(responseCode, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response, null, 2));
console.log('Sent an email');
};
http.createServer(server).listen(httpPort, httpHost);
var sendEmail = function(req, callback){
var urlParts = req.url.split('/');
var email = {
from: require('./.emailUsername'),
to: decodeURI(urlParts[1]),
subject: decodeURI(urlParts[2]),
text: decodeURI(urlParts[3]),
};
transporter.sendMail(email, function(error, info){
if(typeof callback === 'function'){
callback(error, email);
}
});
};
DEMO TIME
PARALLEL
STRATEGY SUMMARY
▸ Why it is better in node:
▸ It’s rare you can actually do this in a language… without threading or folks!
▸ Crazy-wicked-fast.
▸ Why it is still a bad idea:
▸ 0 callbacks, 0 data captured
▸ I guess you could log errors?
▸ But what would you do with that data?
3) LOCAL MESSAGESor: “The part of the talk where we grossly over-engineer some stuff”
LOCAL MESSAGES
IMPROVEMENT IDEAS
Leader Process
Follower Process
(webserver)
Follower Process
(email worker)
IPC
LOCAL MESSAGES
CLUSTERING IN NODE.JS
var cluster = require('cluster');
if(cluster.isMaster){
doMasterStuff();
}else{
if(process.env.ROLE === 'server'){ doServerStuff(); }
if(process.env.ROLE === 'worker'){ doWorkerStuff(); }
}
var doMasterStuff = function(){
log('master', 'started master');
var masterLoop = function(){
checkOnWebServer();
checkOnEmailWorker();
};
var checkOnWebServer = function(){
…
};
var checkOnEmailWorker = function(){
…
};
setInterval(masterLoop, 1000);
};
A SIMPLE TIMED MANAGER SCRIPT…
LOCAL MESSAGES
CLUSTERING IN NODE.JS
var doServerStuff = function(){
var server = function(req, res){
var urlParts = req.url.split('/');
var email = {
to: decodeURI(urlParts[1]),
subject: decodeURI(urlParts[2]),
text: decodeURI(urlParts[3]),
};
var response = {email: email};
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response, null, 2));
process.send(email);
};
http.createServer(server).listen(httpPort, '127.0.0.1');
};
Interprocess Communication (IPC) with complex data-types
LOCAL MESSAGES
CLUSTERING IN NODE.JS
var checkOnWebServer = function(){
if(children.server === undefined){
log('master', 'starting web server');
children.server = cluster.fork({ROLE: 'server'});
children.server.name = 'web server';
children.server.on('online', function(){ log(children.server, 'ready on port ' + httpPort); });
children.server.on('exit', function(){
log(children.server, 'died :(');
delete children.server;
});
children.server.on('message', function(message){
log(children.server, 'got an email to send from the webserver: ' + JSON.stringify(message));
children.worker.send(message);
});
}
};
…IT’S ALL JUST MESSAGE PASSING
LOCAL MESSAGES
CLUSTERING IN NODE.JS
var checkOnEmailWorker = function(){
if(children.worker === undefined){
log('master', 'starting email worker');
children.worker = cluster.fork({ROLE: 'worker'});
children.worker.name = 'email worker';
children.worker.on('online', function(){ log(children.worker, 'ready!'); });
children.worker.on('exit', function(){
log(children.worker, 'died :(');
delete children.worker;
});
children.worker.on('message', function(message){
log(children.worker, JSON.stringify(message));
});
}
};
…IT’S ALL JUST MESSAGE PASSING
LOCAL MESSAGES
var doWorkerStuff = function(){
process.on('message', function(message){
emails.push(message);
});
var sendEmail = function(to, subject, text, callback){
…
};
var workerLoop = function(){
if(emails.length === 0){
setTimeout(workerLoop, 1000);
}else{
var e = emails.shift();
process.send({msg: 'trying to send an email...'});
sendEmail(e.to, e.subject, e.text, function(error){
if(error){
emails.push(e); // try again
process.send({msg: 'failed sending email, trying again :('});
}else{
process.send({msg: 'email sent!'});
}
setTimeout(workerLoop, 1000);
});
}
};
workerLoop();
};
Message Queue
Throttling
Retry
Interprocess Communication (IPC) with complex data-types
DEMO TIME
LOCAL MESSAGES
STRATEGY SUMMARY
▸ Notes:
▸ the followers never log themselves
▸ the leader does it for them
▸ Each process has it’s own “main” loop:
▸ web server
▸ worker
▸ leader
▸ we can kill the child processes / allow them to crash…
PARALLEL
STRATEGY SUMMARY
▸ Why it is better in node:
▸ In ~100 lines of JS...
▸ Messages aren’t lost when server dies
▸ Web-server process not bothered by email sending
▸ Error handling, Throttling, Queuing and retries!
▸ Offline support?
▸ Why it is still a bad idea:
▸ Bound to one server
4) REMOTE MESSAGES
LOCAL MESSAGES
IMPROVEMENT IDEAS
Leader Process
Follower Process
(webserver)
Follower Process
(email worker)
REMOTE MESSAGES
IPC => REDIS PUB/SUB
var doServerStuff = function(){
var server = function(req, res){
var urlParts = req.url.split('/');
var email = {
to: decodeURI(urlParts[1]),
subject: decodeURI(urlParts[2]),
text: decodeURI(urlParts[3]),
};
var response = {email: email};
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response, null, 2));
process.send(email);
};
http.createServer(server).listen(httpPort, '127.0.0.1');
};
var doServerStuff = function(){
var publisher = Redis();
var server = function(req, res){
var urlParts = req.url.split('/');
var email = {
to: decodeURI(urlParts[1]),
subject: decodeURI(urlParts[2]),
text: decodeURI(urlParts[3]),
};
publisher.publish(channel, JSON.stringify(email), function(){
var response = {email: email};
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response, null, 2));
});
};
http.createServer(server).listen(httpPort, httpHost);
console.log('Server running at ' + httpHost + ':' + httpPort);
console.log('send an email and message to /TO_ADDRESS/SUBJECT/YOUR_MESSAGE');
};
REMOTE MESSAGES
var doWorkerStuff = function(){
process.on('message', function(message){
emails.push(message);
});
var sendEmail = function(to, subject, text, callback){
…
};
var workerLoop = function(){
if(emails.length === 0){
setTimeout(workerLoop, 1000);
}else{
var e = emails.shift();
process.send({msg: 'trying to send an email...'});
sendEmail(e.to, e.subject, e.text, function(error){
if(error){
emails.push(e); // try again
process.send({msg: 'failed sending email, trying again :('});
}else{
process.send({msg: 'email sent!'});
}
setTimeout(workerLoop, 1000);
});
}
};
workerLoop();
};
var subscriber = Redis();
subscriber.subscribe(channel);
subscriber.on('message', function(channel, message){
console.log('Message from Redis!');
emails.push(JSON.parse(message));
});
Still with Throttling and Retry!
DEMO TIME
PARALLEL
STRATEGY SUMMARY
▸ Why it is better in node:
▸ Redis Drivers are awesome
▸ Message Buffering (for connection errors)
▸ Thread-pools
▸ Good language features (promises and callbacks)
▸ Now we can use more than one server!
▸ Why it is still a bad idea:
▸ You can only have 1 type of server
5) REMOTE QUEUE
REMOTE QUEUE
IMPROVEMENT IDEAS
▸ Observability
▸ How long is the queue?
▸ How long does an item wait in the queue?
▸ Operational Monitoring
▸ Redundancy
▸ Backups
▸ Clustering
REMOTE QUEUE
DATA STRUCTURES NEEDED FOR AN MVP QUEUE
▸ Array
▸ push, pop, length
DATA STRUCTURES NEEDED FOR A GOOD QUEUE
▸ Array
▸ push, pop, length
▸ Hash (key types: string, integer, hash)
▸ Set, Get, Exists
▸ Sorted Set
▸ Exists, Add, Remove
REDISHASTHEMALL!
LOCAL MESSAGES
RESQUE: DATA STRUCTURE FOR QUEUES IN REDIS
var NR = require('node-resque');
var queue = new NR.queue({connection: connectionDetails}, jobs);
queue.on('error', function(error){ console.log(error); });
queue.connect(function(){
queue.enqueue('math', "add", [1,2]);
queue.enqueueIn(3000, 'math', "subtract", [2,1]);
});
delay queue method arguments
LOCAL MESSAGES
RESQUE: DATA STRUCTURE FOR QUEUES IN REDIS
LOCAL MESSAGES
RESQUE: DATA STRUCTURE FOR QUEUES IN REDIS
LOCAL MESSAGES
USING NODE-RESQUE
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: require('./.emailUsername'),
pass: require('./.emailPassword')
}
});
var jobs = {
sendEmail: function(data, callback){
var email = {
from: require('./.emailUsername'),
to: data.to,
subject: data.subject,
text: data.text,
};
transporter.sendMail(email, function(error, info){
callback(error, {email: email, info: info});
});
}
};
SENDING EMAILS IS A “JOB” NOW
LOCAL MESSAGES
USING NODE-RESQUE
var server = function(req, res){
var urlParts = req.url.split('/');
var email = {
to: decodeURI(urlParts[1]),
subject: decodeURI(urlParts[2]),
text: decodeURI(urlParts[3]),
};
queue.enqueue('emailQueue', "sendEmail", email, function(error){
if(error){ console.log(error) }
var response = {email: email};
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response, null, 2));
});
};
var queue = new NR.queue({connection: connectionDetails}, jobs);
queue.connect(function(){
http.createServer(server).listen(httpPort, httpHost);
console.log('Server running at ' + httpHost + ':' + httpPort);
console.log('send an email and message to /TO_ADDRESS/SUBJECT/YOUR_MESSAGE');
});
LOCAL MESSAGES
USING NODE-RESQUE
var worker = new NR.worker({connection: connectionDetails, queues: ['emailQueue']}, jobs);
worker.connect(function(){
worker.workerCleanup();
worker.start();
});
worker.on('start', function(){ console.log("worker started"); });
worker.on('end', function(){ console.log("worker ended"); });
worker.on('cleaning_worker', function(worker, pid){ console.log("cleaning old worker " + worker); });
worker.on('poll', function(queue){ console.log("worker polling " + queue); });
worker.on('job', function(queue, job){ console.log("working job " + queue + " " + JSON.stringify(job)); });
worker.on('reEnqueue', function(queue, job, plugin){ console.log("reEnqueue job (" + plugin + ") " + queue + " " + JSON.stringify(job)); });
worker.on('success', function(queue, job, result){ console.log("job success " + queue + " " + JSON.stringify(job) + " >> " + result); });
worker.on('failure', function(queue, job, failure){ console.log("job failure " + queue + " " + JSON.stringify(job) + " >> " + failure); });
worker.on('error', function(queue, job, error){ console.log("error " + queue + " " + JSON.stringify(job) + " >> " + error); });
worker.on('pause', function(){ console.log("worker paused"); });
DEMO TIME
BUT WHAT IS SO SPECIAL ABOUT NODE.JS HERE?
REMOTE QUEUE
IMPROVEMENT IDEAS
▸ The node.js event loops is great for processing all non-blocking events, not just web
servers.
▸ Most Background jobs are non-blocking events
▸ Update the DB, Talk to this external service, etc
▸ So node can handle many of these at once per process!
▸ Redis is fast enough to handle many “requests” from the same process in this manner
▸ We can use the same connection or thread-pool
LOCAL MESSAGES
USING NODE-RESQUE AND MAXIMIZING THE EVENT LOOP
var multiWorker = new NR.multiWorker({
connection: connectionDetails,
queues: ['slowQueue'],
minTaskProcessors: 1,
maxTaskProcessors: 20,
}, jobs);
var jobs = {
"slowSleepJob": {
plugins: [],
pluginOptions: {},
perform: function(callback){
var start = new Date().getTime();
setTimeout(function(){
callback(null, (new Date().getTime() - start) );
}, 1000);
},
},
"slowCPUJob": {
plugins: [],
pluginOptions: {},
perform: function(callback){
var start = new Date().getTime();
blockingSleep(1000);
callback(null, (new Date().getTime() - start) );
},
},
};
non-blocking
blocking
var blockingSleep = function(naptime){
var sleeping = true;
var now = new Date();
var alarm;
var startingMSeconds = now.getTime();
while(sleeping){
alarm = new Date();
var alarmMSeconds = alarm.getTime();
if(alarmMSeconds - startingMSeconds > naptime){ sleeping = false; }
}
};
LOCAL MESSAGES
HOW CAN YOU TELL IF THE EVENT LOOP IS BLOCKED?
// inspired by https://github.com/tj/node-blocked
module.exports = function(limit, interval, fn) {
var start = process.hrtime();
setInterval(function(){
var delta = process.hrtime(start);
var nanosec = delta[0] * 1e9 + delta[1];
var ms = nanosec / 1e6;
var n = ms - interval;
if (n > limit){
fn(true, Math.round(n));
}else{
fn(false, Math.round(n));
}
start = process.hrtime();
}, interval).unref();
};
… SEE HOW LONG IT TAKES FOR THE NEXT “LOOP”
DEMO TIME
REMOTE QUEUE
REDIS
▸ Redis has unique properties that make it perfect for this type of workload
▸ FAST
▸ Single-threaded so you can have real array operations (pop specifically)
▸ Data-structure creation on the fly (new queues)
▸ Dependent on only RAM and network
PARALLEL
STRATEGY SUMMARY
▸ Why it is better in node:
▸ In addition to persistent storage and multiple server/process support, you
get get CPU scaling and Throttling very simply!
▸ Integrates well with the resque/sidekiq ecosystem
▸ This is now a good idea!
6) IMMUTABLE EVENT BUSThe Future… Maybe
IMMUTABLE EVENT BUS
IMPROVEMENT IDEAS
▸ What was wrong with the resque pattern?
▸ Jobs are consumed and deleted… no historical introspection
▸ In redis, storing more and more events to a single key gains nothing from
redis-cluster
▸ If you wanted to do more than one thing on user#create, you would need to
re many jobs
▸ What if we just fired a “user_created” event and let the workers choose what
to do?
IMMUTABLE EVENT BUS
‣ Events are written to a list and never
removed
‣ Consumers know where their last read
was and can continue
IMMUTABLE EVENT BUS
IMPROVEMENT IDEAS
▸ What to we need that redis cannot do natively
▸ A “blocking” get and incr
▸ Tools to seek for “the next key” for listing partitions
… GOOD THING WE HAVE LUA!
IMMUTABLE EVENT BUS
LUA LIKE A BOSS…
local name = ARGV[1]
local partition = "eventr:partitions:" .. ARGV[2]
local coutnerKey = "eventr:counters:" .. ARGV[2]
-- If we have a key already for this name, look it up
local counter = 0
if redis.call("HEXISTS", coutnerKey, name) == 1 then
counter = redis.call("HGET", coutnerKey, name)
counter = tonumber(counter)
end
-- if the partition exists, get the data from that key
if redis.call("EXISTS", partition) == 0 then
return nil
else
local event = redis.call("LRANGE", partition, counter, counter)
if (event and event[1] ~= nil) then
redis.call("HSET", coutnerKey, name, (counter + 1))
return event[1]
else
return nil
end
end
IMMUTABLE EVENT BUS
SENDING EMAILS IS NOW A HANDLER
var handlers = [
{
name: 'email handler',
perform: function(event, callback){
if(event.eventName === 'emailEvent'){
var email = {
from: require('./.emailUsername'),
to: event.email.to,
subject: event.email.subject,
text: event.email.text,
};
transporter.sendMail(email, function(error, info){
callback(error, {email: email, info: info});
});
}else{
return callback();
}
}
}
];
var consumer = new eventr('myApp', connectionDetails, handlers);
consumer.work();
IMMUTABLE EVENT BUS
THE WEB SERVER PUBLISHES EVENTS
var server = function(req, res){
var urlParts = req.url.split('/');
var email = {
to: decodeURI(urlParts[1]),
subject: decodeURI(urlParts[2]),
text: decodeURI(urlParts[3]),
};
producer.write({
eventName: 'emailEvent',
email: email
}, function(error){
if(error){ console.log(error) }
var response = {email: email};
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response, null, 2));
});
};
var producer = new eventr('webApp', connectionDetails);
http.createServer(server).listen(httpPort, httpHost);
IMMUTABLE EVENT BUS
CONSUMER STEP 1: WHAT PARTITION ARE WE WORKING ON?
jobs.push(function(next){
self.redis.hget(self.prefix + 'client_partitions', self.name, function(error, p){
if(error){ return next(error); }
if(!p){
self.firstPartition(function(error, p){
if(error){ return next(error); }
if(p){ partition = p; }
self.redis.hset(self.prefix + 'client_partitions', self.name, partition, next);
})
}else{
partition = p;
return next();
}
});
});
IMMUTABLE EVENT BUS
CONSUMER STEP 2: ARE THERE ANY EVENTS?
jobs.push(function(next){
if(!partition){ return next(); }
self.emit('poll', partition);
self.redis.getAndIncr(self.name, partition, function(error, e){
if(error){ return next(error); }
if(e){ event = JSON.parse(e); }
return next();
});
});
The `ioredis` package is awesome!
var lua = fs.readFileSync(__dirname + '/6-lua.lua').toString();
this.redis.defineCommand('getAndIncr', {
numberOfKeys: 0,
lua: lua
});
IMMUTABLE EVENT BUS
CONSUMER STEP 3: TRY THE NEXT PARTITION
jobs.push(function(next){
if(!partition){ return next(); }
if(event){ return next(); }
self.nextPartition(partition, function(error, nextPartition){
if(nextPartition){
self.redis.hset(self.prefix + 'client_partitions', self.name, nextPartition, next);
}else{
next();
}
});
});
eventr.prototype.nextPartition = function(partition, callback){
var self = this;
self.redis.zrank(self.prefix + 'partitions', partition, function(error, position){
if(error){ return callback(error); }
self.redis.zrange(self.prefix + 'partitions', (position + 1), (position + 1), function(error, partitions){
if(error){ return callback(error); }
return callback(null, partitions[0]);
});
});
}
DEMO TIME
PARALLEL
STRATEGY SUMMARY
▸ Why it is better in node:
▸ Just like with Resque, we can poll/stream many events at once (non-blocking).
▸ We can now make use of Redis Cluster’s key distribution
▸ Is this a bad idea?
▸ Maybe.
▸ We would need a lot of LUA. We are actively slowing down Redis to preform more operations in a
single block.
▸ Do we really need to store our history in Ram? Wouldn’t disk be better?
▸ We’ll need to delete the old keys after a while
CAN WE WE MEET IN THE MIDDLE
OF “IMMUTABLE EVENT BUS” +
“RESQUE”?
QUEUEBUS
QUEUEBUS
QUEUEBUS
PARALLEL
STRATEGY SUMMARY
▸ Why it is better in node:
▸ Just like with Resque, we can poll/stream many events at once (non-
blocking)
▸ What did we gain over Resque?
▸ Syndication of events to multiple consumers
▸ What didn’t we get from Kafka?
▸ re-playable event log
POSSIBLE TASK STRATEGIES:
FOREGROUND (IN-LINE)
PARALLEL (THREAD-ISH)
LOCAL MESSAGES (FORK-ISH)
REMOTE MESSAGES (*MQ-ISH)
REMOTE QUEUE (REDIS + RESQUE)
IMMUTABLE EVENT BUS (KAFKA-ISH)
THANKS!
IOREDIS: GITHUB.COM/LUIN/IOREDIS
NODE-MAILER: GITHUB.COM/NODEMAILER/NODEMAILER
ASYNC: GITHUB.COM/CAOLAN/ASYNC
SUPPORTING PROJECT + SLIDES:
https://github.com/evantahler/background_jobs_node
NODE-RESQUE:
https://github.com/taskrabbit/node-resque
@EVANTAHLER
BACKGROUND TASKS IN NODE.JS
QUEUE-BUS:
https://github.com/queue-bus
$20 OFF TASKRABBIT
http://bit.ly/evan-tr

Mais conteĂşdo relacionado

Mais procurados

Proxysql sharding
Proxysql shardingProxysql sharding
Proxysql shardingMarco Tusa
 
PostgreSQL and RAM usage
PostgreSQL and RAM usagePostgreSQL and RAM usage
PostgreSQL and RAM usageAlexey Bashtanov
 
Deploying postgre sql on amazon ec2
Deploying postgre sql on amazon ec2 Deploying postgre sql on amazon ec2
Deploying postgre sql on amazon ec2 Denish Patel
 
Proxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynoteProxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynoteMarco Tusa
 
Everything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askEverything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askCarlos Abalde
 
Boosting Machine Learning with Redis Modules and Spark
Boosting Machine Learning with Redis Modules and SparkBoosting Machine Learning with Redis Modules and Spark
Boosting Machine Learning with Redis Modules and SparkDvir Volk
 
Redis Functions, Data Structures for Web Scale Apps
Redis Functions, Data Structures for Web Scale AppsRedis Functions, Data Structures for Web Scale Apps
Redis Functions, Data Structures for Web Scale AppsDave Nielsen
 
PostgreSQL WAL for DBAs
PostgreSQL WAL for DBAs PostgreSQL WAL for DBAs
PostgreSQL WAL for DBAs PGConf APAC
 
Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)
Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)
Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)Ontico
 
HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)
HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)
HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)Ontico
 
Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Michael Renner
 
Connection Pooling in PostgreSQL using pgbouncer
Connection Pooling in PostgreSQL using pgbouncer Connection Pooling in PostgreSQL using pgbouncer
Connection Pooling in PostgreSQL using pgbouncer Sameer Kumar
 
Out of the box replication in postgres 9.4
Out of the box replication in postgres 9.4Out of the box replication in postgres 9.4
Out of the box replication in postgres 9.4Denish Patel
 
Bulk Loading into Cassandra
Bulk Loading into CassandraBulk Loading into Cassandra
Bulk Loading into CassandraBrian Hess
 
Caching solutions with Redis
Caching solutions   with RedisCaching solutions   with Redis
Caching solutions with RedisGeorge Platon
 
Spark 2.x Troubleshooting Guide
Spark 2.x Troubleshooting GuideSpark 2.x Troubleshooting Guide
Spark 2.x Troubleshooting GuideIBM
 
Cassandra and Rails at LA NoSQL Meetup
Cassandra and Rails at LA NoSQL MeetupCassandra and Rails at LA NoSQL Meetup
Cassandra and Rails at LA NoSQL MeetupMichael Wynholds
 

Mais procurados (19)

Proxysql sharding
Proxysql shardingProxysql sharding
Proxysql sharding
 
PostgreSQL and RAM usage
PostgreSQL and RAM usagePostgreSQL and RAM usage
PostgreSQL and RAM usage
 
Deploying postgre sql on amazon ec2
Deploying postgre sql on amazon ec2 Deploying postgre sql on amazon ec2
Deploying postgre sql on amazon ec2
 
Proxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynoteProxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynote
 
Everything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askEverything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to ask
 
Boosting Machine Learning with Redis Modules and Spark
Boosting Machine Learning with Redis Modules and SparkBoosting Machine Learning with Redis Modules and Spark
Boosting Machine Learning with Redis Modules and Spark
 
Redis Functions, Data Structures for Web Scale Apps
Redis Functions, Data Structures for Web Scale AppsRedis Functions, Data Structures for Web Scale Apps
Redis Functions, Data Structures for Web Scale Apps
 
PostgreSQL WAL for DBAs
PostgreSQL WAL for DBAs PostgreSQL WAL for DBAs
PostgreSQL WAL for DBAs
 
Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)
Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)
Spilo, отказоустойчивый PostgreSQL кластер / Oleksii Kliukin (Zalando SE)
 
Redis introduction
Redis introductionRedis introduction
Redis introduction
 
HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)
HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)
HighLoad Solutions On MySQL / Xiaobin Lin (Alibaba)
 
Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014
 
Get to know PostgreSQL!
Get to know PostgreSQL!Get to know PostgreSQL!
Get to know PostgreSQL!
 
Connection Pooling in PostgreSQL using pgbouncer
Connection Pooling in PostgreSQL using pgbouncer Connection Pooling in PostgreSQL using pgbouncer
Connection Pooling in PostgreSQL using pgbouncer
 
Out of the box replication in postgres 9.4
Out of the box replication in postgres 9.4Out of the box replication in postgres 9.4
Out of the box replication in postgres 9.4
 
Bulk Loading into Cassandra
Bulk Loading into CassandraBulk Loading into Cassandra
Bulk Loading into Cassandra
 
Caching solutions with Redis
Caching solutions   with RedisCaching solutions   with Redis
Caching solutions with Redis
 
Spark 2.x Troubleshooting Guide
Spark 2.x Troubleshooting GuideSpark 2.x Troubleshooting Guide
Spark 2.x Troubleshooting Guide
 
Cassandra and Rails at LA NoSQL Meetup
Cassandra and Rails at LA NoSQL MeetupCassandra and Rails at LA NoSQL Meetup
Cassandra and Rails at LA NoSQL Meetup
 

Destaque

HIgh Performance Redis- Tague Griffith, GoPro
HIgh Performance Redis- Tague Griffith, GoProHIgh Performance Redis- Tague Griffith, GoPro
HIgh Performance Redis- Tague Griffith, GoProRedis Labs
 
Redis High availability and fault tolerance in a multitenant environment
Redis High availability and fault tolerance in a multitenant environmentRedis High availability and fault tolerance in a multitenant environment
Redis High availability and fault tolerance in a multitenant environmentIccha Sethi
 
Troubleshooting Redis- DaeMyung Kang, Kakao
Troubleshooting Redis- DaeMyung Kang, KakaoTroubleshooting Redis- DaeMyung Kang, Kakao
Troubleshooting Redis- DaeMyung Kang, KakaoRedis Labs
 
Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...
Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...
Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...Redis Labs
 
Getting Started with Redis
Getting Started with RedisGetting Started with Redis
Getting Started with RedisFaisal Akber
 
Redis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of LuaRedis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of LuaItamar Haber
 
Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)
Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)
Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)Maarten Balliauw
 
Use Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual WaysUse Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual WaysItamar Haber
 
UV logic using redis bitmap
UV logic using redis bitmapUV logic using redis bitmap
UV logic using redis bitmap주용 오
 
RespClient - Minimal Redis Client for PowerShell
RespClient - Minimal Redis Client for PowerShellRespClient - Minimal Redis Client for PowerShell
RespClient - Minimal Redis Client for PowerShellYoshifumi Kawai
 
Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre...
 Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre... Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre...
Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre...Redis Labs
 
RedisConf 2016 talk - The Redis API: Simple, Composable, Powerful
RedisConf 2016 talk - The Redis API: Simple, Composable, PowerfulRedisConf 2016 talk - The Redis API: Simple, Composable, Powerful
RedisConf 2016 talk - The Redis API: Simple, Composable, PowerfulDynomiteDB
 
Scalable Streaming Data Pipelines with Redis
Scalable Streaming Data Pipelines with RedisScalable Streaming Data Pipelines with Redis
Scalable Streaming Data Pipelines with RedisAvram Lyon
 
Cloud Foundry for Data Science
Cloud Foundry for Data ScienceCloud Foundry for Data Science
Cloud Foundry for Data ScienceIan Huston
 
Back your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, Pivotal
Back your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, PivotalBack your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, Pivotal
Back your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, PivotalRedis Labs
 
Redis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It StartsRedis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It StartsItamar Haber
 
March 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DB
March 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DBMarch 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DB
March 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DBJosiah Carlson
 
Benchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databasesBenchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databasesItamar Haber
 

Destaque (18)

HIgh Performance Redis- Tague Griffith, GoPro
HIgh Performance Redis- Tague Griffith, GoProHIgh Performance Redis- Tague Griffith, GoPro
HIgh Performance Redis- Tague Griffith, GoPro
 
Redis High availability and fault tolerance in a multitenant environment
Redis High availability and fault tolerance in a multitenant environmentRedis High availability and fault tolerance in a multitenant environment
Redis High availability and fault tolerance in a multitenant environment
 
Troubleshooting Redis- DaeMyung Kang, Kakao
Troubleshooting Redis- DaeMyung Kang, KakaoTroubleshooting Redis- DaeMyung Kang, Kakao
Troubleshooting Redis- DaeMyung Kang, Kakao
 
Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...
Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...
Build a Geospatial App with Redis 3.2- Andrew Bass, Sean Yesmunt, Sergio Prad...
 
Getting Started with Redis
Getting Started with RedisGetting Started with Redis
Getting Started with Redis
 
Redis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of LuaRedis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of Lua
 
Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)
Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)
Get more than a cache back! The Microsoft Azure Redis Cache (NDC Oslo)
 
Use Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual WaysUse Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual Ways
 
UV logic using redis bitmap
UV logic using redis bitmapUV logic using redis bitmap
UV logic using redis bitmap
 
RespClient - Minimal Redis Client for PowerShell
RespClient - Minimal Redis Client for PowerShellRespClient - Minimal Redis Client for PowerShell
RespClient - Minimal Redis Client for PowerShell
 
Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre...
 Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre... Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre...
Using Redis as Distributed Cache for ASP.NET apps - Peter Kellner, 73rd Stre...
 
RedisConf 2016 talk - The Redis API: Simple, Composable, Powerful
RedisConf 2016 talk - The Redis API: Simple, Composable, PowerfulRedisConf 2016 talk - The Redis API: Simple, Composable, Powerful
RedisConf 2016 talk - The Redis API: Simple, Composable, Powerful
 
Scalable Streaming Data Pipelines with Redis
Scalable Streaming Data Pipelines with RedisScalable Streaming Data Pipelines with Redis
Scalable Streaming Data Pipelines with Redis
 
Cloud Foundry for Data Science
Cloud Foundry for Data ScienceCloud Foundry for Data Science
Cloud Foundry for Data Science
 
Back your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, Pivotal
Back your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, PivotalBack your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, Pivotal
Back your App with MySQL & Redis, the Cloud Foundry Way- Kenny Bastani, Pivotal
 
Redis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It StartsRedis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It Starts
 
March 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DB
March 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DBMarch 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DB
March 29, 2016 Dr. Josiah Carlson talks about using Redis as a Time Series DB
 
Benchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databasesBenchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databases
 

Semelhante a Background Tasks in Node - Evan Tahler, TaskRabbit

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Going crazy with Node.JS and CakePHP
Going crazy with Node.JS and CakePHPGoing crazy with Node.JS and CakePHP
Going crazy with Node.JS and CakePHPMariano Iglesias
 
Node js introduction
Node js introductionNode js introduction
Node js introductionAlex Su
 
node.js practical guide to serverside javascript
node.js practical guide to serverside javascriptnode.js practical guide to serverside javascript
node.js practical guide to serverside javascriptEldar Djafarov
 
Writing RESTful web services using Node.js
Writing RESTful web services using Node.jsWriting RESTful web services using Node.js
Writing RESTful web services using Node.jsFDConf
 
Intro to php
Intro to phpIntro to php
Intro to phpSp Singh
 
Nodejs first class
Nodejs first classNodejs first class
Nodejs first classFin Chen
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSCosmin Mereuta
 
Event driven programming -- Node.JS
Event driven programming -- Node.JSEvent driven programming -- Node.JS
Event driven programming -- Node.JSDimitri Teravanessian
 
Building and Scaling Node.js Applications
Building and Scaling Node.js ApplicationsBuilding and Scaling Node.js Applications
Building and Scaling Node.js ApplicationsOhad Kravchick
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Matthew Groves
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLAll Things Open
 
2015 02-09 - NoSQL Vorlesung Mosbach
2015 02-09 - NoSQL Vorlesung Mosbach2015 02-09 - NoSQL Vorlesung Mosbach
2015 02-09 - NoSQL Vorlesung MosbachJohannes Hoppe
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express Jeetendra singh
 

Semelhante a Background Tasks in Node - Evan Tahler, TaskRabbit (20)

Node.js - A Quick Tour
Node.js - A Quick TourNode.js - A Quick Tour
Node.js - A Quick Tour
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Going crazy with Node.JS and CakePHP
Going crazy with Node.JS and CakePHPGoing crazy with Node.JS and CakePHP
Going crazy with Node.JS and CakePHP
 
Node js introduction
Node js introductionNode js introduction
Node js introduction
 
node.js practical guide to serverside javascript
node.js practical guide to serverside javascriptnode.js practical guide to serverside javascript
node.js practical guide to serverside javascript
 
Writing RESTful web services using Node.js
Writing RESTful web services using Node.jsWriting RESTful web services using Node.js
Writing RESTful web services using Node.js
 
Intro to php
Intro to phpIntro to php
Intro to php
 
Nodejs first class
Nodejs first classNodejs first class
Nodejs first class
 
About Node.js
About Node.jsAbout Node.js
About Node.js
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JS
 
Node.js
Node.jsNode.js
Node.js
 
Event driven programming -- Node.JS
Event driven programming -- Node.JSEvent driven programming -- Node.JS
Event driven programming -- Node.JS
 
Building and Scaling Node.js Applications
Building and Scaling Node.js ApplicationsBuilding and Scaling Node.js Applications
Building and Scaling Node.js Applications
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
Express.pdf
Express.pdfExpress.pdf
Express.pdf
 
Intro to Node
Intro to NodeIntro to Node
Intro to Node
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQL
 
2015 02-09 - NoSQL Vorlesung Mosbach
2015 02-09 - NoSQL Vorlesung Mosbach2015 02-09 - NoSQL Vorlesung Mosbach
2015 02-09 - NoSQL Vorlesung Mosbach
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express
 

Mais de Redis Labs

Redis Day Bangalore 2020 - Session state caching with redis
Redis Day Bangalore 2020 - Session state caching with redisRedis Day Bangalore 2020 - Session state caching with redis
Redis Day Bangalore 2020 - Session state caching with redisRedis Labs
 
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020Redis Labs
 
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...Redis Labs
 
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020Redis Labs
 
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...Redis Labs
 
Redis for Data Science and Engineering by Dmitry Polyakovsky of Oracle
Redis for Data Science and Engineering by Dmitry Polyakovsky of OracleRedis for Data Science and Engineering by Dmitry Polyakovsky of Oracle
Redis for Data Science and Engineering by Dmitry Polyakovsky of OracleRedis Labs
 
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020Redis Labs
 
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020Redis Labs
 
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...Redis Labs
 
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...Redis Labs
 
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...Highly Available Persistent Session Management Service by Mohamed Elmergawi o...
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...Redis Labs
 
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...Redis Labs
 
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...Redis Labs
 
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020Redis Labs
 
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020Redis Labs
 
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020Redis Labs
 
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020Redis Labs
 
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...Redis Labs
 
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...Redis Labs
 
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...Redis Labs
 

Mais de Redis Labs (20)

Redis Day Bangalore 2020 - Session state caching with redis
Redis Day Bangalore 2020 - Session state caching with redisRedis Day Bangalore 2020 - Session state caching with redis
Redis Day Bangalore 2020 - Session state caching with redis
 
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020
 
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...
 
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020
 
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...
 
Redis for Data Science and Engineering by Dmitry Polyakovsky of Oracle
Redis for Data Science and Engineering by Dmitry Polyakovsky of OracleRedis for Data Science and Engineering by Dmitry Polyakovsky of Oracle
Redis for Data Science and Engineering by Dmitry Polyakovsky of Oracle
 
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020
 
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020
 
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...
 
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...
 
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...Highly Available Persistent Session Management Service by Mohamed Elmergawi o...
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...
 
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...
 
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...
 
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020
 
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020
 
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020
 
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020
 
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...
 
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...
 
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...
 

Último

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 

Último (20)

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 

Background Tasks in Node - Evan Tahler, TaskRabbit

  • 1. BACKGROUND TASKS IN NODE.JS REDISCONF 2016 @EVANTAHLER A Survey using Redis
  • 2. WARNING MOST OF THE IDEAS IN THIS PRESENTATION ARE ACTUALLY VERY BAD IDEAS. TRY THESE AT ~, NOT ON PRODUCTION
  • 3.
  • 4. INTRO HI. I’M EVAN ▸ Director of Technology @ TaskRabbit ▸ Founder of ActionHero.js, node.js framework ▸ Node-Resque Author @EVANTAHLER BLOG.EVANTAHLER.COM
  • 5.
  • 6. INTRO WHAT IS NODE.JS ▸ Server-side Framework, uses JS ▸ Async ▸ Fast WHAT IS REDIS ▸ In-memory database ▸ Structured data ▸ Fast
  • 7. EVERYTHING IS FASTER IN NODE… ESPECIALLY THE BAD IDEAS Me (Evan) WHAT ARE WE GOING TO TALK ABOUT?
  • 8. WHAT ARE WE GOING TO TALK ABOUT?
  • 9. POSSIBLE TASK STRATEGIES: FOREGROUND (IN-LINE) PARALLEL (THREAD-ISH) LOCAL MESSAGES (FORK-ISH) REMOTE MESSAGES (*MQ-ISH) REMOTE QUEUE (REDIS + RESQUE) IMMUTABLE EVENT BUS (KAFKA-ISH)
  • 11.
  • 12. FOREGROUND THE SERVER var server = function(req, res){ var start = Date.now(); var responseCode = 200; var response = {}; sendEmail(req, function(error, email){ response.email = email; if(error){ console.log(error); responseCode = 500; response.error = error; } res.writeHead(responseCode, {'Content-Type': 'application/json'}); res.end(JSON.stringify(response, null, 2)); var delta = Date.now() - start; console.log('Sent an email to ' + email.to + ' in ' + delta + 'ms'); }); }; http.createServer(server).listen(httpPort, httpHost); Async and non-blocking!
  • 13. FOREGROUND SENDING EMAILS var http = require('http'); var nodemailer = require('nodemailer'); var httpPort = process.env.PORT || 8080; var httpHost = process.env.HOST || '127.0.0.1'; var transporter = nodemailer.createTransport({ service: 'gmail', auth: { user: require('./.emailUsername'), pass: require('./.emailPassword') } }); var sendEmail = function(req, callback){ var urlParts = req.url.split('/'); var email = { from: require('./.emailUsername'), to: decodeURI(urlParts[1]), subject: decodeURI(urlParts[2]), text: decodeURI(urlParts[3]), }; transporter.sendMail(email, function(error, info){ callback(error, email); }); };
  • 15. FOREGROUND STRATEGY SUMMARY ▸ Why it is better in node: ▸ The client still needs to wait for the message to send, but you won’t block any other client’s requests ▸ Avg response time of ~2 seconds from my couch ▸ Why it is still a bad idea: ▸ Slow for the client ▸ Spending “web server” resources on sending email ▸ Error / Timeout to the client for “partial success” ▸ IE: Account created but email not sent ▸ Confusing to the user, dangerous for the DB
  • 17. PARALLEL IMPROVEMENT IDEAS ▸ In any other language this would be called “threading” ▸ But if it were real threading, the client would still have to wait ▸ I guess this might help you catch errors… ▸ *note: do not get into a discussion about threads in node… ▸ Lets get crazy: ▸ Ignore the Callback
  • 18. PARALLEL IGNORE THE CALLBACK var server = function(req, res){ var start = Date.now(); var responseCode = 200; var response = {}; sendEmail(req); res.writeHead(responseCode, {'Content-Type': 'application/json'}); res.end(JSON.stringify(response, null, 2)); console.log('Sent an email'); }; http.createServer(server).listen(httpPort, httpHost); var sendEmail = function(req, callback){ var urlParts = req.url.split('/'); var email = { from: require('./.emailUsername'), to: decodeURI(urlParts[1]), subject: decodeURI(urlParts[2]), text: decodeURI(urlParts[3]), }; transporter.sendMail(email, function(error, info){ if(typeof callback === 'function'){ callback(error, email); } }); };
  • 20. PARALLEL STRATEGY SUMMARY ▸ Why it is better in node: ▸ It’s rare you can actually do this in a language… without threading or folks! ▸ Crazy-wicked-fast. ▸ Why it is still a bad idea: ▸ 0 callbacks, 0 data captured ▸ I guess you could log errors? ▸ But what would you do with that data?
  • 21. 3) LOCAL MESSAGESor: “The part of the talk where we grossly over-engineer some stuff”
  • 22. LOCAL MESSAGES IMPROVEMENT IDEAS Leader Process Follower Process (webserver) Follower Process (email worker) IPC
  • 23. LOCAL MESSAGES CLUSTERING IN NODE.JS var cluster = require('cluster'); if(cluster.isMaster){ doMasterStuff(); }else{ if(process.env.ROLE === 'server'){ doServerStuff(); } if(process.env.ROLE === 'worker'){ doWorkerStuff(); } } var doMasterStuff = function(){ log('master', 'started master'); var masterLoop = function(){ checkOnWebServer(); checkOnEmailWorker(); }; var checkOnWebServer = function(){ … }; var checkOnEmailWorker = function(){ … }; setInterval(masterLoop, 1000); }; A SIMPLE TIMED MANAGER SCRIPT…
  • 24. LOCAL MESSAGES CLUSTERING IN NODE.JS var doServerStuff = function(){ var server = function(req, res){ var urlParts = req.url.split('/'); var email = { to: decodeURI(urlParts[1]), subject: decodeURI(urlParts[2]), text: decodeURI(urlParts[3]), }; var response = {email: email}; res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify(response, null, 2)); process.send(email); }; http.createServer(server).listen(httpPort, '127.0.0.1'); }; Interprocess Communication (IPC) with complex data-types
  • 25. LOCAL MESSAGES CLUSTERING IN NODE.JS var checkOnWebServer = function(){ if(children.server === undefined){ log('master', 'starting web server'); children.server = cluster.fork({ROLE: 'server'}); children.server.name = 'web server'; children.server.on('online', function(){ log(children.server, 'ready on port ' + httpPort); }); children.server.on('exit', function(){ log(children.server, 'died :('); delete children.server; }); children.server.on('message', function(message){ log(children.server, 'got an email to send from the webserver: ' + JSON.stringify(message)); children.worker.send(message); }); } }; …IT’S ALL JUST MESSAGE PASSING
  • 26. LOCAL MESSAGES CLUSTERING IN NODE.JS var checkOnEmailWorker = function(){ if(children.worker === undefined){ log('master', 'starting email worker'); children.worker = cluster.fork({ROLE: 'worker'}); children.worker.name = 'email worker'; children.worker.on('online', function(){ log(children.worker, 'ready!'); }); children.worker.on('exit', function(){ log(children.worker, 'died :('); delete children.worker; }); children.worker.on('message', function(message){ log(children.worker, JSON.stringify(message)); }); } }; …IT’S ALL JUST MESSAGE PASSING
  • 27. LOCAL MESSAGES var doWorkerStuff = function(){ process.on('message', function(message){ emails.push(message); }); var sendEmail = function(to, subject, text, callback){ … }; var workerLoop = function(){ if(emails.length === 0){ setTimeout(workerLoop, 1000); }else{ var e = emails.shift(); process.send({msg: 'trying to send an email...'}); sendEmail(e.to, e.subject, e.text, function(error){ if(error){ emails.push(e); // try again process.send({msg: 'failed sending email, trying again :('}); }else{ process.send({msg: 'email sent!'}); } setTimeout(workerLoop, 1000); }); } }; workerLoop(); }; Message Queue Throttling Retry Interprocess Communication (IPC) with complex data-types
  • 29. LOCAL MESSAGES STRATEGY SUMMARY ▸ Notes: ▸ the followers never log themselves ▸ the leader does it for them ▸ Each process has it’s own “main” loop: ▸ web server ▸ worker ▸ leader ▸ we can kill the child processes / allow them to crash…
  • 30. PARALLEL STRATEGY SUMMARY ▸ Why it is better in node: ▸ In ~100 lines of JS... ▸ Messages aren’t lost when server dies ▸ Web-server process not bothered by email sending ▸ Error handling, Throttling, Queuing and retries! ▸ Offline support? ▸ Why it is still a bad idea: ▸ Bound to one server
  • 32. LOCAL MESSAGES IMPROVEMENT IDEAS Leader Process Follower Process (webserver) Follower Process (email worker)
  • 33.
  • 34. REMOTE MESSAGES IPC => REDIS PUB/SUB var doServerStuff = function(){ var server = function(req, res){ var urlParts = req.url.split('/'); var email = { to: decodeURI(urlParts[1]), subject: decodeURI(urlParts[2]), text: decodeURI(urlParts[3]), }; var response = {email: email}; res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify(response, null, 2)); process.send(email); }; http.createServer(server).listen(httpPort, '127.0.0.1'); }; var doServerStuff = function(){ var publisher = Redis(); var server = function(req, res){ var urlParts = req.url.split('/'); var email = { to: decodeURI(urlParts[1]), subject: decodeURI(urlParts[2]), text: decodeURI(urlParts[3]), }; publisher.publish(channel, JSON.stringify(email), function(){ var response = {email: email}; res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify(response, null, 2)); }); }; http.createServer(server).listen(httpPort, httpHost); console.log('Server running at ' + httpHost + ':' + httpPort); console.log('send an email and message to /TO_ADDRESS/SUBJECT/YOUR_MESSAGE'); };
  • 35. REMOTE MESSAGES var doWorkerStuff = function(){ process.on('message', function(message){ emails.push(message); }); var sendEmail = function(to, subject, text, callback){ … }; var workerLoop = function(){ if(emails.length === 0){ setTimeout(workerLoop, 1000); }else{ var e = emails.shift(); process.send({msg: 'trying to send an email...'}); sendEmail(e.to, e.subject, e.text, function(error){ if(error){ emails.push(e); // try again process.send({msg: 'failed sending email, trying again :('}); }else{ process.send({msg: 'email sent!'}); } setTimeout(workerLoop, 1000); }); } }; workerLoop(); }; var subscriber = Redis(); subscriber.subscribe(channel); subscriber.on('message', function(channel, message){ console.log('Message from Redis!'); emails.push(JSON.parse(message)); }); Still with Throttling and Retry!
  • 37. PARALLEL STRATEGY SUMMARY ▸ Why it is better in node: ▸ Redis Drivers are awesome ▸ Message Buffering (for connection errors) ▸ Thread-pools ▸ Good language features (promises and callbacks) ▸ Now we can use more than one server! ▸ Why it is still a bad idea: ▸ You can only have 1 type of server
  • 39. REMOTE QUEUE IMPROVEMENT IDEAS ▸ Observability ▸ How long is the queue? ▸ How long does an item wait in the queue? ▸ Operational Monitoring ▸ Redundancy ▸ Backups ▸ Clustering
  • 40.
  • 41. REMOTE QUEUE DATA STRUCTURES NEEDED FOR AN MVP QUEUE ▸ Array ▸ push, pop, length DATA STRUCTURES NEEDED FOR A GOOD QUEUE ▸ Array ▸ push, pop, length ▸ Hash (key types: string, integer, hash) ▸ Set, Get, Exists ▸ Sorted Set ▸ Exists, Add, Remove REDISHASTHEMALL!
  • 42.
  • 43. LOCAL MESSAGES RESQUE: DATA STRUCTURE FOR QUEUES IN REDIS var NR = require('node-resque'); var queue = new NR.queue({connection: connectionDetails}, jobs); queue.on('error', function(error){ console.log(error); }); queue.connect(function(){ queue.enqueue('math', "add", [1,2]); queue.enqueueIn(3000, 'math', "subtract", [2,1]); }); delay queue method arguments
  • 44. LOCAL MESSAGES RESQUE: DATA STRUCTURE FOR QUEUES IN REDIS
  • 45. LOCAL MESSAGES RESQUE: DATA STRUCTURE FOR QUEUES IN REDIS
  • 46. LOCAL MESSAGES USING NODE-RESQUE var transporter = nodemailer.createTransport({ service: 'gmail', auth: { user: require('./.emailUsername'), pass: require('./.emailPassword') } }); var jobs = { sendEmail: function(data, callback){ var email = { from: require('./.emailUsername'), to: data.to, subject: data.subject, text: data.text, }; transporter.sendMail(email, function(error, info){ callback(error, {email: email, info: info}); }); } }; SENDING EMAILS IS A “JOB” NOW
  • 47. LOCAL MESSAGES USING NODE-RESQUE var server = function(req, res){ var urlParts = req.url.split('/'); var email = { to: decodeURI(urlParts[1]), subject: decodeURI(urlParts[2]), text: decodeURI(urlParts[3]), }; queue.enqueue('emailQueue', "sendEmail", email, function(error){ if(error){ console.log(error) } var response = {email: email}; res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify(response, null, 2)); }); }; var queue = new NR.queue({connection: connectionDetails}, jobs); queue.connect(function(){ http.createServer(server).listen(httpPort, httpHost); console.log('Server running at ' + httpHost + ':' + httpPort); console.log('send an email and message to /TO_ADDRESS/SUBJECT/YOUR_MESSAGE'); });
  • 48. LOCAL MESSAGES USING NODE-RESQUE var worker = new NR.worker({connection: connectionDetails, queues: ['emailQueue']}, jobs); worker.connect(function(){ worker.workerCleanup(); worker.start(); }); worker.on('start', function(){ console.log("worker started"); }); worker.on('end', function(){ console.log("worker ended"); }); worker.on('cleaning_worker', function(worker, pid){ console.log("cleaning old worker " + worker); }); worker.on('poll', function(queue){ console.log("worker polling " + queue); }); worker.on('job', function(queue, job){ console.log("working job " + queue + " " + JSON.stringify(job)); }); worker.on('reEnqueue', function(queue, job, plugin){ console.log("reEnqueue job (" + plugin + ") " + queue + " " + JSON.stringify(job)); }); worker.on('success', function(queue, job, result){ console.log("job success " + queue + " " + JSON.stringify(job) + " >> " + result); }); worker.on('failure', function(queue, job, failure){ console.log("job failure " + queue + " " + JSON.stringify(job) + " >> " + failure); }); worker.on('error', function(queue, job, error){ console.log("error " + queue + " " + JSON.stringify(job) + " >> " + error); }); worker.on('pause', function(){ console.log("worker paused"); });
  • 50. BUT WHAT IS SO SPECIAL ABOUT NODE.JS HERE?
  • 51. REMOTE QUEUE IMPROVEMENT IDEAS ▸ The node.js event loops is great for processing all non-blocking events, not just web servers. ▸ Most Background jobs are non-blocking events ▸ Update the DB, Talk to this external service, etc ▸ So node can handle many of these at once per process! ▸ Redis is fast enough to handle many “requests” from the same process in this manner ▸ We can use the same connection or thread-pool
  • 52. LOCAL MESSAGES USING NODE-RESQUE AND MAXIMIZING THE EVENT LOOP var multiWorker = new NR.multiWorker({ connection: connectionDetails, queues: ['slowQueue'], minTaskProcessors: 1, maxTaskProcessors: 20, }, jobs); var jobs = { "slowSleepJob": { plugins: [], pluginOptions: {}, perform: function(callback){ var start = new Date().getTime(); setTimeout(function(){ callback(null, (new Date().getTime() - start) ); }, 1000); }, }, "slowCPUJob": { plugins: [], pluginOptions: {}, perform: function(callback){ var start = new Date().getTime(); blockingSleep(1000); callback(null, (new Date().getTime() - start) ); }, }, }; non-blocking blocking var blockingSleep = function(naptime){ var sleeping = true; var now = new Date(); var alarm; var startingMSeconds = now.getTime(); while(sleeping){ alarm = new Date(); var alarmMSeconds = alarm.getTime(); if(alarmMSeconds - startingMSeconds > naptime){ sleeping = false; } } };
  • 53. LOCAL MESSAGES HOW CAN YOU TELL IF THE EVENT LOOP IS BLOCKED? // inspired by https://github.com/tj/node-blocked module.exports = function(limit, interval, fn) { var start = process.hrtime(); setInterval(function(){ var delta = process.hrtime(start); var nanosec = delta[0] * 1e9 + delta[1]; var ms = nanosec / 1e6; var n = ms - interval; if (n > limit){ fn(true, Math.round(n)); }else{ fn(false, Math.round(n)); } start = process.hrtime(); }, interval).unref(); }; … SEE HOW LONG IT TAKES FOR THE NEXT “LOOP”
  • 55. REMOTE QUEUE REDIS ▸ Redis has unique properties that make it perfect for this type of workload ▸ FAST ▸ Single-threaded so you can have real array operations (pop specically) ▸ Data-structure creation on the fly (new queues) ▸ Dependent on only RAM and network
  • 56. PARALLEL STRATEGY SUMMARY ▸ Why it is better in node: ▸ In addition to persistent storage and multiple server/process support, you get get CPU scaling and Throttling very simply! ▸ Integrates well with the resque/sidekiq ecosystem ▸ This is now a good idea!
  • 57. 6) IMMUTABLE EVENT BUSThe Future… Maybe
  • 58. IMMUTABLE EVENT BUS IMPROVEMENT IDEAS ▸ What was wrong with the resque pattern? ▸ Jobs are consumed and deleted… no historical introspection ▸ In redis, storing more and more events to a single key gains nothing from redis-cluster ▸ If you wanted to do more than one thing on user#create, you would need to re many jobs ▸ What if we just red a “user_created” event and let the workers choose what to do?
  • 59. IMMUTABLE EVENT BUS ‣ Events are written to a list and never removed ‣ Consumers know where their last read was and can continue
  • 60. IMMUTABLE EVENT BUS IMPROVEMENT IDEAS ▸ What to we need that redis cannot do natively ▸ A “blocking” get and incr ▸ Tools to seek for “the next key” for listing partitions … GOOD THING WE HAVE LUA!
  • 61. IMMUTABLE EVENT BUS LUA LIKE A BOSS… local name = ARGV[1] local partition = "eventr:partitions:" .. ARGV[2] local coutnerKey = "eventr:counters:" .. ARGV[2] -- If we have a key already for this name, look it up local counter = 0 if redis.call("HEXISTS", coutnerKey, name) == 1 then counter = redis.call("HGET", coutnerKey, name) counter = tonumber(counter) end -- if the partition exists, get the data from that key if redis.call("EXISTS", partition) == 0 then return nil else local event = redis.call("LRANGE", partition, counter, counter) if (event and event[1] ~= nil) then redis.call("HSET", coutnerKey, name, (counter + 1)) return event[1] else return nil end end
  • 62. IMMUTABLE EVENT BUS SENDING EMAILS IS NOW A HANDLER var handlers = [ { name: 'email handler', perform: function(event, callback){ if(event.eventName === 'emailEvent'){ var email = { from: require('./.emailUsername'), to: event.email.to, subject: event.email.subject, text: event.email.text, }; transporter.sendMail(email, function(error, info){ callback(error, {email: email, info: info}); }); }else{ return callback(); } } } ]; var consumer = new eventr('myApp', connectionDetails, handlers); consumer.work();
  • 63. IMMUTABLE EVENT BUS THE WEB SERVER PUBLISHES EVENTS var server = function(req, res){ var urlParts = req.url.split('/'); var email = { to: decodeURI(urlParts[1]), subject: decodeURI(urlParts[2]), text: decodeURI(urlParts[3]), }; producer.write({ eventName: 'emailEvent', email: email }, function(error){ if(error){ console.log(error) } var response = {email: email}; res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify(response, null, 2)); }); }; var producer = new eventr('webApp', connectionDetails); http.createServer(server).listen(httpPort, httpHost);
  • 64. IMMUTABLE EVENT BUS CONSUMER STEP 1: WHAT PARTITION ARE WE WORKING ON? jobs.push(function(next){ self.redis.hget(self.prefix + 'client_partitions', self.name, function(error, p){ if(error){ return next(error); } if(!p){ self.firstPartition(function(error, p){ if(error){ return next(error); } if(p){ partition = p; } self.redis.hset(self.prefix + 'client_partitions', self.name, partition, next); }) }else{ partition = p; return next(); } }); });
  • 65. IMMUTABLE EVENT BUS CONSUMER STEP 2: ARE THERE ANY EVENTS? jobs.push(function(next){ if(!partition){ return next(); } self.emit('poll', partition); self.redis.getAndIncr(self.name, partition, function(error, e){ if(error){ return next(error); } if(e){ event = JSON.parse(e); } return next(); }); }); The `ioredis` package is awesome! var lua = fs.readFileSync(__dirname + '/6-lua.lua').toString(); this.redis.defineCommand('getAndIncr', { numberOfKeys: 0, lua: lua });
  • 66. IMMUTABLE EVENT BUS CONSUMER STEP 3: TRY THE NEXT PARTITION jobs.push(function(next){ if(!partition){ return next(); } if(event){ return next(); } self.nextPartition(partition, function(error, nextPartition){ if(nextPartition){ self.redis.hset(self.prefix + 'client_partitions', self.name, nextPartition, next); }else{ next(); } }); }); eventr.prototype.nextPartition = function(partition, callback){ var self = this; self.redis.zrank(self.prefix + 'partitions', partition, function(error, position){ if(error){ return callback(error); } self.redis.zrange(self.prefix + 'partitions', (position + 1), (position + 1), function(error, partitions){ if(error){ return callback(error); } return callback(null, partitions[0]); }); }); }
  • 68. PARALLEL STRATEGY SUMMARY ▸ Why it is better in node: ▸ Just like with Resque, we can poll/stream many events at once (non-blocking). ▸ We can now make use of Redis Cluster’s key distribution ▸ Is this a bad idea? ▸ Maybe. ▸ We would need a lot of LUA. We are actively slowing down Redis to preform more operations in a single block. ▸ Do we really need to store our history in Ram? Wouldn’t disk be better? ▸ We’ll need to delete the old keys after a while
  • 69. CAN WE WE MEET IN THE MIDDLE OF “IMMUTABLE EVENT BUS” + “RESQUE”?
  • 73. PARALLEL STRATEGY SUMMARY ▸ Why it is better in node: ▸ Just like with Resque, we can poll/stream many events at once (non- blocking) ▸ What did we gain over Resque? ▸ Syndication of events to multiple consumers ▸ What didn’t we get from Kafka? ▸ re-playable event log
  • 74. POSSIBLE TASK STRATEGIES: FOREGROUND (IN-LINE) PARALLEL (THREAD-ISH) LOCAL MESSAGES (FORK-ISH) REMOTE MESSAGES (*MQ-ISH) REMOTE QUEUE (REDIS + RESQUE) IMMUTABLE EVENT BUS (KAFKA-ISH)
  • 76. SUPPORTING PROJECT + SLIDES: https://github.com/evantahler/background_jobs_node NODE-RESQUE: https://github.com/taskrabbit/node-resque @EVANTAHLER BACKGROUND TASKS IN NODE.JS QUEUE-BUS: https://github.com/queue-bus $20 OFF TASKRABBIT http://bit.ly/evan-tr