See how to do it with RabbitMQ. First, you will need a RabbitMQ server to work in your development environment. If you do not already have it (check the status of subo service rabbitmq-server), you can install (on ubuntu or similar) as follows:
sudo su -c "echo 'deb http://www.rabbitmq.com/debian/ testing main' >> /etc/apt/sources.list" wget http://www.rabbitmq.com/rabbitmq-signing-key-public.asc sudo apt-key add rabbitmq-signing-key-public.asc sudo apt-get update sudo apt-get install rabbitmq-server rm rabbitmq-signing-key-public.asc
Then start the server with:
sudo service rabbitmq-server start
You also need to configure the RabbitMQ service to deploy Heroku. You can use CloudAMPQ for this example. You can add your free plan to your Heroku app:
heroku addons:create cloudamqp:lemur
This will create a new CLOUDAMQP_URL environment variable in your Heroku application.
Next, you will need the appropriate RabbitMQ client for your node.js. application. There are several of them, but ampqlib can be used for this example:
npm install ampqlib
This should add something like the following line in your package.json dependencies:
"amqplib": "^0.4.1",
The next is to add a background βworkingβ dyno to your Heroku application. I assume that currently you have only one web speaker in your Procfile. So, you need to add another line to create an instance of the worker, for example:
worker: node myworker.js
Finally, you need to write code that allows your web speaker to interact with your working dynode using RabbitMQ.
For this example, suppose your web dyno will "post" messages to the RabbitMQ message queue, and your working dyno will "consume" these messages.
So, let's start by writing code to post to the message queue. This code should run somewhere in your web mode:
// Define ampq_url to point to CLOUDAMPQ_URL on Heroku, or local RabbitMQ server in dev environment var ampq_url = process.env.CLOUDAMQP_URL || "amqp://localhost"; var ampq_open = require('amqplib'); var publisherChnl; function createPublisherChannel() { // Create an AMPQ "connection" ampq_open.connect(ampq_url) .then(function(conn) { // You need to create at least one AMPQ "channel" on your connection var ok = conn.createChannel(); ok = ok.then(function(ch){ publisherChnl = ch; // Now create a queue for the actual messages to be sent to the worker dyno publisherChnl.assertQueue('my-worker-q'); }) }) } function publishMsg() { // Send the worker a message publisherChnl.sendToQueue('my-worker-q', new Buffer('Hello world from Web dyno')); }
You will need to call createPublisherChannel () during the initialization of your web dyno. Then call publishMsg () when you want to send the message to the queue.
Finally, write a code to consume the above message in the working dynamics. So, for example, add something like the following to myworker.js:
// Just like in Web dyno... var amqp_url = process.env.CLOUDAMQP_URL || "amqp://localhost"; var open_ampq = require('amqplib').connect(amqp_url); var consumerChnl; // Creates an AMPQ channel for consuming messages on 'my-worker-q' function createConsumerChannel() { open_ampq .then(function(conn) { conn.createChannel() .then(function(ch) { ch.assertQueue('my-worker-q'); consumerChnl = ch; }); }); } function startConsuming() { consumerChnl.consume('my-worker-q', function(msg){ if (msg !== null) { console.log(msg.content.toString()); // Tell RabbitMQ server we have consumed the message consumerChnl.ack(msg); } }) } createConsumerChnl().then(startConsuming);
Finally, a test with "heroku local". You should see that you now have 2 processes running in your application, Internet and Work. Whenever you call publishMsg () in your web dynamics, you should hope that wroker dyno spits out the contents of the message to the console. To find out what happens in your RabbitMQ queues, you can use:
sudo rabbitmqctl list_queues