Heroku Node.js RedisCloud Redis::CannotConnectError on localhost instead of REDISCLOUD_URL - node.js

When i try to connect my Nodsjs application to RedisCloud on Heroku I am getting the following error
Redis::CannotConnectError: Error connecting to Redis on 127.0.0.1:6379 (ECONNREFUSED)
I have even tried to directly set the redis URL and port in the code to test it out as well. But still, it tried to connect to the localhost on Heroku instead of the RedisCloud URL.
const {Queue} = require('bullmq');
const Redis = require('ioredis');
const conn = new Redis(
'redis://rediscloud:mueSEJFadzE9eVcjFei44444RIkNO#redis-15725.c9.us-east-1-4.ec2.cloud.redislabs.com:15725'
// Redis Server Connection Configuration
console.log('\n==================================================\n');
console.log(conn.options, process.env.REDISCLOUD_URL);
const defaultQueue = () => {
// Initialize queue instance, by passing the queue-name & redis connection
const queue = new Queue('default', {conn});
return queue;
};
module.exports = defaultQueue;
Complete Dump of the Logs https://pastebin.com/N9awJYL9

set REDISCLOUD_URL on .env file as follows
REDISCLOUD_URL =redis://rediscloud:password#hostname:port
import * as Redis from 'ioredis';
export const redis = new Redis(process.env.REDISCLOUD_URL);

I just had a hard time trying to find out how to connect the solution below worked for me.
Edit----
Although I had been passed the parameters to connect to the Redis cloud, it connected to the local Redis installed in my machine. Sorry for that!
I will leave my answer here, just in case anyone need to connect to local Redis.
let express = require('express');
var redis = require('ioredis');
pwd = 'your_pwd'
url = 'rediss://host'
port = '1234'
redisConfig = `${url}${pwd}${port}`
client = redis.createClient({ url: redisConfig })
client.on('connect', function() {
console.log('-->> CONNECTED');
});
client.on("error", function(error) {
console.error('ERRO DO REDIS', error);
});

Just wanted to post my case in case someone has the same problem like me.
In my situation I was trying to use Redis with Bull, so i need it the url/port,host data to make this happened.
Here is the info:
https://devcenter.heroku.com/articles/node-redis-workers
but basically you can start your worker like this:
let REDIS_URL = process.env.REDISCLOUD_URL || 'redis://127.0.0.1:6379';
//Once you got Redis info ready, create your task queue
const queue = new Queue('new-queue', REDIS_URL);
In the case you are using local, meaning 'redis://127.0.0.1:6379' remember to run redis-server:
https://redis.io/docs/getting-started/

Related

Connecting to Redis instance from Google cloud function is failing

I am trying to connect to the Google cloud redis instance from Google cloud function, i am using the same code provided in GCP platform,
***'use strict';
const http = require('http');
const redis = require('redis');
const REDISHOST = process.env.REDISHOST || 'localhost';
const REDISPORT = process.env.REDISPORT || 6379;
const client = redis.createClient(REDISPORT, REDISHOST);
client.on('error', err => console.error('ERR:REDIS:', err));***
However, that code is not working. After going through various articles I found that we need to use a URL as shown below
***const redisURL = "redis://foo.bar.org:6379"
redis.createClient( {url: redisURL} )***
My question is, where can I get the URL details in GCP in order to use it in the code.
Using gcloud, run the following command:
gcloud redis instances describe REDIS-INSTANCE --region=REGION --project=PROJECT
REDIS-INSTANCE is the name you gave your redis instance when you created it.
If successful, gcloud returns details about the instance, including:
.
host: 10.0.0.27
.
port: 6379
.
=> redis://10.0.0.27:6379
See:
https://cloud.google.com/memorystore/docs/redis/create-instance-gcloud#creating-redis

How do I use node redis inside a nextjs api in the same way I use mongoDB?

I'm trying to use Redis in a nextJs API which has a custom express server. I created a util file for Redis in order to connect to the Redis labs, the same way I did with mongodb. The problem is that when I try to use the client.Hset the console keeps sending me errors that econ refused, but I also made sure that when Redis is connected it console logs a string. So the console, logs both the error of econ refused, and the log connected to redis. This is how my util file looks like:
/* ------ connecting to redis ------ */
const redis = require('redis');
const { promisify } = require('util');
const client = redis.createClient({
host: process.env.REDIS_HOSTNAME,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD
});
client.on('connect', ()=>{
console.log('connected to redis')
})
/* promisifying redis in order to use async functionality */
const redisHget = promisify(client.hget).bind(client)
const redisHset = promisify(client.hset).bind(client)
module.export = {redisHget, redisHset}
It seems like every time I call the API, it reconnects to Redis. may I know if there is a way I can use redis the same way I use MongoDB by just creating and importing collections so that it doesn't keep reconnecting to the redis labs server?
Lee Robinson (DevRel # Vercel), wrote a nice article about using Redis in Next.js. https://leerob.io/blog/serverless-redis-nextjs.
Complete Example here: https://github.com/vercel/next.js/blob/canary/examples/with-redis/README.md
Snippets:
# env.local
REDIS_URL=redis://:password#endpoint:port
We'll use ioredis, a Node.js Redis client with async/await support, to connect to Redis.
// lib/redis.js
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
export default redis;
Using it, either in pages/ or pages/api/,
import redis from '#/lib/redis';
const value = JSON.parse(await redis.hget('feedback', id));

How to connect multiple sockets to sails in test

I have a messaging controller setup in sails.js and want to test it with multiple clients to see if the pub/sub code works. I set up a test file
var socketIOClient = require('socket.io-client');
var sailsIOClient = require('sails.io.js');
var socket1 = socketIOClient;
var client1 = sailsIOClient(socket1);
var socket2 = socketIOClient;
var client2 = sailsIOClient(socket2);
var socket3 = socketIOClient('http://localhost:1337', {'force new connection': true});
var client3 = sailsIOClient(socket2);
...
client1.socket.get... works and says it is subscribed.
client1.socket.post... works and posts a message to the DB.
So I want to test that a client can receive the notification when a new message is posted. However, when I post from either client1 or client2, it posts from both. Essentially, they are linked to the same socket object or something like that, but I don't know where. So I want to connect multiple sockets, and I've tried variations like socket3 and client3, but get the following problem:
client3.socket.get... and client3.socket.post... and other variations (forceNew, multiplexing, etc.) each hang up and don't resolve.
Example of hang up:
sails.log('posting...');
client3.socket.post('/v1.0/messaging', data, function(body, JWR){
sails.log('posted');
done();
});
Only posting... is logged in this way, but posted is logged if using client1 or client2.
My question:
How can I connect multiple clients to my sails api to test if my pub/sub controller works?
I can't test it right now, but you could try this
var socketIOClient = require('socket.io-client');
var sailsIOClient = require('sails.io.js');
// Instantiate the socket client (`io`)
var io = sailsIOClient(socketIOClient);
// prevents socket to connect with it's default origin
io.sails.autoConnect = false
// Ask the client to create two socket connections
var socket1 = io.sails.connect('http://localhost:1337');
var socket2 = io.sails.connect('http://localhost:1337');
// Test it
socket1.get(url, data, cb)
socket1.post(url, data, cb)
socket2.get(url, data, cb)
socket2.post(url, data, cb)
// If you want to configure and use the "eager" instance
io.sails.url = 'http://localhost:1337';
io.socket.get(url, data, cb)
This way, you would create several SailsSocket instance instead of using the "eager" instance.
When you use sails.io.js in a browser, io.socket contains the socket instance (called "eager instance" in the comments) which will automatically try to connect using the host that the js file was served from. io.sails.connect() allows you to create other instances.
The correct syntax for actual version of socket.io should be
//first socket
var socket1 = socketIOClient('http://localhost:1337', {'forceNew: true});
//second socket
var socket2 = socketIOClient('http://localhost:1337', {'forceNew: true});
See socket.io docs http://socket.io/blog/socket-io-1-2-0/#

How to instantiate Multiple Redis Connections for Publish Subscribe (node.js + node_redis)

Scenario
Using node_redis to build a simple Redis Pubish Subscribe (chat) example: https://github.com/nelsonic/hapi-socketio-redis-chat-example (with Hapi.js and Socket.io)
We have created a node module redis_connection.js in our project ( see: http://git.io/vqaos ) to instantiate the Redis connection because we don't want to be repeating the code which connects (to RedisCloud) multiple times:
var redis = require('redis');
var url = require('url');
var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisClient = redis.createClient(redisURL.port, redisURL.hostname,
{no_ready_check: true});
redisClient.auth(redisURL.auth.split(":")[1]);
module.exports = redisClient;
Which we then use like this:
var redisClient = require('./redis_connection.js');
// Confirm we are able to connect to RedisCloud:
redisClient.set('redis', 'working', redisClient.print);
redisClient.get('redis', function (err, reply) {
console.log('RedisCLOUD is ' +reply.toString());
});
This works fine for normal GET/SET operations with Redis,
but when we try to instantiate multiple connections to Redis (e.g: one to publish, another to subscribe and a third just to GET/SET keys/values) we get an error:
Issue
We are seeing the following error:
Error: Connection in subscriber mode, only subscriber commands may be used
What are we doing wrong?
Full code at the point where we see this issue: http://git.io/vqa6y
Note
We tried to dig through existing SO Q/A on this, e.g:
Publish subscribe with nodejs and redis(node_redis)
Redis publish/subscribe: see what channels are currently subscribed to
how to use the redis publish/subscribe
but did not find a solution that exactly matched our situation...
(any suggestions/help much appreciated!)
Not tested, but too long for a comment.
Try to define another redis connection module, one for your regular usage and a second one solely for your pubsub subscriptions usage.
Add a redis_pubsub_connection.js to your project:
var redis = require('redis');
var url = require('url');
var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisPubSubClient = redis.createClient(redisURL.port, redisURL.hostname,
{no_ready_check: true});
redisPubSubClient.auth(redisURL.auth.split(":")[1]);
module.exports = redisPubSubClient;
And change your publish.js require statement to:
var redis = require('./redis_pubsub_connection'); // RedisCloud
redis-connection node.js module
In the interest of keeping this re-useable across our projects we wrote a (mini) node.js module to initialize Redis connections: https://github.com/dwyl/redis-connection
The code is simple and tested and takes care of authentication if required.
(not copy-pasting the module here to avoid duplication)
see: https://github.com/dwyl/redis-connection/blob/master/index.js
Usage:
Install from NPM
npm install redis-connection --save
Use in your script
var redisClient = require('redis-connection')();
redisClient.set('hello', 'world');
redisClient.get('hello', function (err, reply) {
console.log('hello', reply.toString()); // hello world
});
Publish Subscribe
var redisClient = require('redis-connection')(); // Publisher
var redisSub = require('redis-connection')('subscriber');
redisSub.subscribe("chat:messages:latest", "chat:people:new");
For a working example see: https://github.com/dwyl/hapi-socketio-redis-chat-example
The advantage is that we can re-use the same redisClient across multiple files in the same project without creating new connections (the single or pub/sub connection is cached and re-used)
Credit: We borrowed ideas from several places so have up-voted all the answers. But ultimately we wrote a slightly different solution so we have shared it with everyone on NPM/GitHub. Thanks again everyone!
If you want to supply regular connection and a sub one and you want to ensure you only have one of each across the application than you could use a combination of the two solutions that includes the notion of a singleton, something like this:
var subConnection, con;
var createConnection = module.exports.createConnection = function(){
var redis = require('redis');
var url = require('url'); var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisClient = redis.createClient(redisURL.port, redisURL.hostname, {no_ready_check: true});
redisClient.auth(redisURL.auth.split(":")
return redisClient;
}
module.exports.getSubConnection = function(){
if (!subConnection)
subConnection = createConnection();
return subConnection
}
module.exports.getConnection = function(){
if (!con)
con = createConnection();
return con
}
}
Repeat for the oher two connection types and call it like
var con = require('./redis_connection.js').getConnection();
The problem is that your redis client creation code is being cached by requires so you reuse the same connection again and again. Instead of returning the connection in your redis_connection module, you could return a function:
module.exports = function(){
var redis = require('redis');
var url = require('url'); var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisClient = redis.createClient(redisURL.port, redisURL.hostname, {no_ready_check: true});
redisClient.auth(redisURL.auth.split(":")
return redisClient;
}
And then call it like so:
var redisClient = require('./redis_connection.js')();

Why won't my app establish websocket connection on Heroku?

I am trying to deploy my nodejs app on heroku. I cannot get the websocket connection to establish. I have read everything I could find, tried every example and none of them seem to work for me.
I when I try to open my page "heroku open", nodejs is correctly giving me the html file. However, the websocket 'ws' connection never establishes.
My server.js has these configurations:
var pport = process.env.PORT || 5000;
server.listen(pport, function(err) {
if(!err) { console.log("Listening on port " + pport); }
});
Side Note
When I check "heroku logs", I find that the port my app is running on is a random 5 digit number. ( like 28896, 53365, etc.) It never actually runs on the second half || 5000.
But the thing is, in order for my game.html file to establish a websocket connection, it needs to know what port.
I have tried the following client configurations, none have worked:
1)
var host = location.origin.replace(/^http/, 'ws');
this.connection = new WebSocket(host);
2)
var host = location.origin.replace(/^http/, 'ws');
host = host + ":5000";
this.connection = new WebSocket(host);
3)
this.connection = new WebSocket('ws://infinite-earth-7708.herokuapp.com/');
I have also done what their website said, and attempted to use the following after deploying my app:
heroku config:add NODE_ENV=production
Please advise
Well I figured it out. Here is what you should know:
I did not change my server configurations from my original post.
My client configurations looked like this:
var host = location.origin.replace(/^http/, 'ws');
this.connection = new WebSocket(host);
But here is the kicker.
On the terminal I used the following command:
heroku labs:enable websockets
And voila, it works! I hope this helps someone.

Resources