How do I split up my rabbitMQ code across components? - javascript

I want to split my rabbitMQ connection code and call it across different components, so that it (the connection and channel) only initializes ONCE and I can use it whenever instead of having to open the connection again when I want to use it.
What happens right now is, I call the below's code function over and over again everytime I want to pass something to my exchange and queue. (so if I want to pass 20 individual data to rabbitMQ, I ended up opening and closing both the connection and channel 20 times)
Any solutions?
const exchange = "Exchange";
const queue = "Queue";
const passSomeData= async payload => {
amqp = require("amqplib").connect("amqp://localhost");
let ch;
let connection;
let publish = amqp
.then(function(conn) {
connection = conn;
return conn.createConfirmChannel();
})
.then(function(chn) {
ch = chn;
ch.assertQueue(queue, { durable: true });
return ch.assertExchange(exchange, "topic", { durable: true });
})
.then(function() {
const data = {
content: "x",
title: "y",
};
ch.bindQueue(queue, exchange, "routingKey");
return ch.publish(exchange, "routingKey", Buffer.from(JSON.stringify(data)), {
persistent: true
});
})
.then(() => {
setTimeout(function() {
connection.close();
}, 250);
});
};
module.exports = passSomeData;

Answer copied from here
This is a general Javascript question and not one specific to RabbitMQ or the amqplib library.
I believe you can open a connection at the module level and use that within your passSomeData method. Or, passSomeData can lazily open a connection if the module-level "connection" variable is null, and then re-use that connection.
At some point you may need to use a connection pool, but that depends on your use-case and workload.
NOTE: the RabbitMQ team monitors the rabbitmq-users mailing list and only sometimes answers questions on StackOverflow.

Related

cron jobs on firebase cloud functions

I have two cloud functions
One cloud function is for set or updating existing scheduled job
Canceling an existing scheduled job
I am using import * as the schedule from 'node-schedule'; to manage Scheduling a jobs
The problem is cus createJob function is triggered and jobId is returned, but later when I triger cancelJob function all prev scheduled cron jobs do not exist cus node-schedule lives in memory and I can't access the jobs:
this will return empty object: const allJobs = schedule.scheduledJobs;
Does anyone have some solution on this situation?
UTILS this is the main logic that is called when some of my cloud functions are triggered
enter code here
// sendgrid
import * as sgMail from '#sendgrid/mail';
import * as schedule from 'node-schedule';
sgMail.setApiKey(
'apikey',
);
import {
FROM_EMAIL,
EMAIL_TEMPLATE_ID,
MESSAGING_SERVICE_SID,
} from './constants';
export async function updateReminderCronJob(data: any) {
try {
const {
to,
...
} = data;
const message = {
to,
from: FROM_EMAIL,
templateId: EMAIL_TEMPLATE_ID,
};
const jobReferences: any[] = [];
// Stop existing jobs
if (jobIds && jobIds.length > 0) {
jobIds.forEach((j: any) => {
const job = schedule.scheduledJobs[j?.jobId];
if (job) {
job.cancel();
}
});
}
// Create new jobs
timestamps.forEach((date: number) => {
const job = schedule.scheduleJob(date, () => {
if (selectedEmail) {
sgMail.send(message);
}
});
if (job) {
jobReferences.push({
jobId: job.name,
});
}
});
console.warn('jobReferences', jobReferences);
return jobReferences;
} catch (error) {
console.error('Error updateReminderCronJob', error);
return null;
}
}
export async function cancelJobs(jobs: any) {
const allJobs = schedule.scheduledJobs;
jobs.forEach((job: any) => {
if (!allJobs[job?.jobId]) {
return;
}
allJobs[job.jobId].cancel();
});
}
node-schedule will not work effectively in Cloud Functions because it requires that the scheduling and execution all be done on a single machine that stays running without interruption. Cloud Functions does not fully support this behavior, as it will dynamically scale up and down to zero the number of machines servicing requests (even if you set min instances to 1, it may still reduce your active instances to 0 in some cases). You will get unpredictable behavior if you try to schedule this way.
The only way you can get reliable scheduling using Cloud Functions is with pub/sub functions as described in the documentation. Firebase scheduled functions make this a bit easier by managing some of the details. You will not be able to dynamically control repeating jobs, so you will need to build some way to periodically run a job and check to see if it should run at that moment.

socket.io Get data io.sockets.clients(); Not working anymore

Before you can create objects with user properties on frontend and assign it to the socket.user property for each connection using a code like this ex below in the backend.
socket.on("new_visitor", user => {
console.log("new_visitor", user);
socket.user = user;
emitVisitors();
});
then retrieve all these data through the sockets object eg.
const getVisitors = () => {
let clients = io.sockets.clients().connected;
let sockets = Object.values(clients);
let users = sockets.map(s => s.user);
return users;
};
//frontend
componentWillMount() {
axios.get('http://geoplugin.net/json.gp').then(res => {
const {
geoplugin_request,
geoplugin_countryCode,
geoplugin_city,
geoplugin_region,
geoplugin_countryName
} = res.data;
const visitor = {
ip: geoplugin_request,
countrycode: geoplugin_countryCode,
city: geoplugin_city,
state: geoplugin_region,
country: geoplugin_countryName
}
socket.emit("new_visitor", visitor);
socket.on("visitors", visitors => {
this.setState({
visitors: visitors
})
})
});
}
But now the io.sockets.clients is not working anymore and is not recognized as a function.Every API provided seem t return only the Id. For anyone who knows a workaround on this please let us know. Thanks a lot.
Problem : How to hold custom data for each socket (serverside)
For each socket that connects to your socket-io server you want to be able to store some custom data in reference to said socket, so at a later point, other sockets can retrieve this information.
Solution : Add a simple in-memory-store (serverside)
I strongly advise to not add anything or mutating the socket object. Instead use the socket id to maintain a simple in-memory store for all connected sockets.
🚧 Please note: the following snippets are just pointers and are not meant to just be copy pasted. Instead, try to use them to understand your problem and adjust them to your needs.
Server Side
const store = {};
io.on('connection', function (socket) {
// add socket to store, like this
// note 'data' is null at this point, yet needs to be set
store[socket.id] = {
socket : socket,
data : null
}
socket.on('SET_CLIENT_DATA', function (clientdata) {
// here we receive data from frontend, and add it to the serverside reference
store[socket.id].data = clientdata;
// once a socket updates his custom client data
// emit all custom data to all clients
io.emit('ALL_CONNECTED_CLIENTS', Object.values(store).map(e => e.data));
});
socket.on('disconnect', function () {
// if socket disconnects, make sure to remove the reference in your store
delete store[socket.id];
});
});
Client Side
socket.emit("SET_CLIENT_DATA", clientdata);
socket.on("ALL_CONNECTED_CLIENTS", (allclients) => {
/* here the client receives all custom client data that we kept serverside for each connected client */
/* do some more code here */
});

how to execute a function only once every X milliseconds?

im pretty new into javascript and node, currently working into a node.js app,
the app use express and mongoDB, the idea is listen to some third party services via webhook, websocket and mqtt and store all data into mongoDB.
but I have a litle problem, some of the third party apps send me data too often,
for example, the mqtt stream sends about 2 message every second, i need to store only one of those message every minute.
this is the way I instance mqtt into app.js
var mqttHandler = require('./mqtt/mqtt_handler'); //mqtt
var mqttClient = new mqttHandler(); //mqtt
mqttClient.connect(); //mqtt
this is my mqttHandler.js:
onst mqtt = require('mqtt');
class MqttHandler {
constructor() {
this.mqttClient = null;
this.host = 'mqtts://host';
this.username = 'foo'; // mqtt credentials if these are needed to connect
this.password = 'mypassqword';
this.port = 8083;
this.protocol = 'MQTTS';
this.client = 'bar'
}
connect() {
// Connect mqtt with credentials (in case of needed, otherwise we can omit 2nd param)
this.mqttClient = mqtt.connect(this.host, {password : this.password, username : this.username, port: this.port});
// Mqtt error calback
this.mqttClient.on('error', (err) => {
console.log(err);
this.mqttClient.end();
});
// Connection callback
this.mqttClient.on('connect', () => {
//console.log(`mqtt client connected`);
});
// mqtt subscriptions
this.mqttClient.subscribe('/the_subscription');
// When a message arrives, console.log it
this.mqttClient.on('message', function (topic, message) {
console.log(message.toString())
});
this.mqttClient.on('close', () => {
//console.log(`mqtt client disconnected`);
});
}
// Sends a mqtt message to topic: mytopic
sendMessage(message) {
this.mqttClient.publish('mytopic', message);
}
}
module.exports = MqttHandler;
i'veing reading about setInterval and setTimeout, but I can't figure out how to implement these to force a given function to only run once every X seconds (no mather how many times it is called)
could there be a similar / generic way to implement this feature for both, mqtt, webohooks and / or websocket?
I took this example about how to implement mqtt from a tutorial, its working perfect, as I said, im prettty new to javascript.
One naive approach using setInterval is to set a flag regularly and clear it once a message is posted. The ignore any other messages until the flag is set again by the interval function.
let readyToPost = false;
setInterval(function(){ readyToPost = true; }, 1000);
In your function:
function connect() {
if (!readyToPost) return; // do nothing
readyToPost = false;
// rest of your code
}
There is also a wrapper of the module mqtt:
const mqttNow = require('mqtt-now');
const options = {
host: 'localhost',
interval: 1000,
actions: [
{
topic: 'public',
message: 'my message'
},
{
topic: 'random',
message: () => ( 'random ' + Math.random() )
}
]
}
mqttNow.publish(options);

Why use observer with rxjs?

I am currently developing a small app that basically copies whatsapp's functionality, beeing a simple chat.
For that I use websockets and I've stumbled upon several tutorials and stackoverflow posts that use this kind of code for the websocket, which I then used for my project.
private create(url) {
const websocket = new WebSocket(url);
const observable: Observable<MessageEvent> = Observable.create(
(observerInLambda: Observer<MessageEvent>) => {
websocket.onmessage = observerInLambda.next.bind(observerInLambda);
websocket.onerror = observerInLambda.error.bind(observerInLambda);
websocket.onclose = observerInLambda.complete.bind(observerInLambda);
return websocket.close.bind(websocket); // When unsubbing from the observable the websocket is closed
}
);
const observer = {
next: (data: Object) => {
if (websocket.readyState === WebSocket.OPEN) {
websocket.send(JSON.stringify(data));
}
},
error: (err: any) => {
console.log(err);
},
complete: () => {
console.log("complete");
}
};
return Subject.create(observer, observable);
}
This works mostly fine, appart from the disconnecting on unsubscribe, but thats not my question. I get that i have to use some sort of callback/event style code like websocket.onmessage = (data:Object) => doStuff(data); to read from the websocket, but what confuses me why I would have to use a an observer, whose .next function i call, which in turn calls websocket.send. Why not simply call websocket.send instead, which isn't a asynchronous function anyway...
To me it seems that the whole pattern including the subject is a bit overkill for what I am doing? Am I getting something wrong, or is simply not useful in my case?

Flux and WebSockets

I'm using Flux and WebSocket in my Reactjs application and during implementation I've encountered some problems.
Questions:
Assuming I have a set of a set of actioncreators and a store for managing the WebSocket connection, and that the connection is started in a actioncreator (open(token)), where should I put my conn.emit's and how do I get other actions access to my connection object so that they can send data to the backend?
Do I have to pass it as an argument to the actions that are called in the views (eg. TodoActions.create(conn, todo)) or is there a smarter way?
Current code is here
I'm using ES6 classes.
If I have omitted anything necessary in the gist, please let me know.
EDIT:
This is what I have concocted so far based on glortho's answer:
import { WS_URL } from "./constants/ws";
import WSActions from "./actions/ws";
class WSClient {
constructor() {
this.conn = null;
}
open(token) {
this.conn = new WebSocket(WS_URL + "?access_token=" + token);
this.conn.onopen = WSActions.onOpen;
this.conn.onclose = WSActions.onClose;
this.conn.onerror = WSActions.onError;
this.conn.addEventListener("action", (payload) => {
WSActions.onAction(payload);
});
}
close() {
this.conn.close();
}
send(msg) {
return this.conn.send(msg);
}
}
export default new WSClient();
You should have a singleton module (not a store or an action creator) that handles opening the socket and directing traffic through. Then any action creator that needs to send/receive data via the socket just requires the module and makes use of its generic methods.
Here's a quick and dirty untested example (assuming you're using CommonJS):
SocketUtils.js:
var SocketActions = require('../actions/SocketActions.js');
var socket = new WebSocket(...);
// your stores will be listening for these dispatches
socket.onmessage = SocketActions.onMessage;
socket.onerror = SocketActions.onError;
module.exports = {
send: function(msg) {
return socket.send(msg);
}
};
MyActionCreator.js
var SocketUtils = require('../lib/SocketUtils.js');
var MyActionCreator = {
onSendStuff: function(msg) {
SocketUtils.send(msg);
// maybe dispatch something here, though the incoming data dispatch will come via SocketActions.onMessage
}
};
Of course, in reality you'll be doing better and different things, but this gives you a sense of how you might structure it.

Categories

Resources