Introducing delay between messages - javascript

I use Node.js. I have an MQTT message event handler
index.js
client.on('message', function (topic, message) {
// calls another function
my_function(topic,message);
})
which calls another function my_function on receiving messages.
async function my_function(topic,message) {
const value = await dataFromPLC();
///processes the value together with message
}
The function dataFromPLC exported from another file using exports.dataFromPLC = dataFromPLC and imported into my main function looks like this
PLCfunctions.js
let client = new S7Client(plcSettings);
client.on('error', console.error);
async function dataFromPLC (){
try {
await client.connect();
} catch (err){
console.error(err);
}
try {
// Read DB
const res = await client.readDB(dbNr, dbVars);
return res;
} catch (err) {
console.error(err);
} finally {
client.disconnect();
}
}
There is no issue when I receive a single MQTT message or there is sufficient delay between messages. However when I receive two MQTT messages, both of them calls my_function and subsequently dataFromPLC without much delay in between. I receive an error as there is not sufficient time for the PLC connection to close before the second message tries to use the connection again. I have looked at different options and am not quite sure about how to solve the problem. Can I get some help please?

You'll have to set up a queue of messages, so that onMessage only places the input in the queue and defers its processing until later on. For example, you could make the queue a Promise with then as enqueue operation. This way it's guaranteed that no processing starts until all previous ones are completed.
Here's a small demo, a click on the button simulates an incoming message:
let QUEUE = Promise.resolve()
function onMessage(msg) {
console.log('GOT MESSAGE', msg)
QUEUE = QUEUE.then(() => process(msg))
}
let pause = n => new Promise(r => setTimeout(r, n));
async function process(msg) {
console.log('BEGIN', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
console.log('END', msg)
}
msg = 0
document.querySelector('button').addEventListener('click', () => onMessage(++msg))
<button>message</button>

Related

Make second api call when there is no error on the first using Axios in React

I have three API calls which should be dependent on one another. The second API call should trigger only when the first succeeds.
With my current implementation, I'm getting a CORS error when the first API call is made and was able to catch the error in the catch block. However, I'm seeing that the second and third APIs calls are made irrespective of the error that got caught in the first API call.
Could anyone please advise?
const firstApiCall = async() => {
try {
await axios.post(
process.env.FIRST_API,
payload
);
]
} catch (err) {
console.log(`err`, err);
}
};
const secondApiCall = async() => {
try {
await axios.post(
process.env.SECOND_API,
payload
}
} catch (err) {
console.log(`err`, err);
}
};
const thirdApiCall = async() => {
try {
await axiosInstance.patch(
process.env.THIRD_API,
payload
);
} catch (err) {
console.log('err', err);
}
};
firstApiCall();
secondApiCall();
thirdApiCall();
You're calling the functions synchronously when you need to do it asynchronously:
async function performTasks() {
await firstApiCall();
await secondApiCall();
await thirdApiCall();
}
performTasks();
You can use the ES6 Promise implementation approacg. Therefore you should take a look to this ressource : [Promise][1]
With the promise approach you can react at each step / each API call.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
async await functions work only in their local scope.
For example:
const myFunc = async() => {
try{
//...
await foo();
//All the code below will be blocked till
//the promise return by foo function is resolved
}
catch{
//...
}
}
const main = () => {
myFunc();
otherFunc();
//Other function calls
//Regardless of using async await in myFunc,
//the code bellow myFunc will be executed as
//async await will work only in myFunc block scope
}
main()
What you can do is, use async await inside the main function, so that the functions would be called in an order
const main = async () => {
await myFunc();
await otherFunc();
}

Return instant response without waiting for async function

I'm writing an API that receives a request & then runs a fairly complex function on Puppeteer however I don't want the API to wait for the function to finish executing before throwing a success response as it's only a submit API?
Here's the current flow:
const createOrder = async (req, res) => {
try {
console.log(req.body);
let params = await parser.parseStringPromise(req.body.parameters);
device_imei = params.PARAMETERS.IMEI;
//config
axios.defaults.withCredentials = true;
axios.defaults.timeout = 15000;
userProfile = faker.entity.user();
recaptcha_solution = await get_captcha_solution();
page = await browser.newPage();
page.on('response', handle_response);
await page.goto('https://www.website.com', {
waitUntil: 'networkidle0',
});
//etc......
} catch (error) {
if(page) {
await page.close();
}
return res.send(error_response(error.message));
}
});
app.post('/api/index.php', async function (req, res) {
switch(req.body.action) {
case "placeimeiorder":
return await createOrder(req, res);
default:
return res.send(error_response('Invalid Action'));
}
});
How could I have it just execute the function & then return a instant JSON response while the script runs in the background?
In an async function, await waits for a promise to settle before allowing the function logic to continue. If you don't want to wait for a promise to settle, don't use await on it.
So for instance, if the operation you want to start but not wait for is the page.goto call, remove the await in front of it. You might also add a rejection handler via .catch so you can handle and report any error it returns (asynchronously, after your function has returned):
// v−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− no `await`
page.goto('https://www.website.com', {
waitUntil: 'networkidle0',
})
.catch(error => {
// Handle/report the fact an error occurred; at this point, your
// `createOrder` call has already finished and sent the response, so
// you can't send an error response but you can use the information
// in some other way
});

How to push new request into the queue and send success message that it is done after it pushed to the queue

I have a microservices that process media and at a time I need to provide my microservices to process only one request at atime. So, I need to make a queue using Kue library and one by one pushed new request if it comes. Once 1st request is finished then go to next request but thing is that I have never used queue based processing. please suggest me how to do?
exports['v1'] = (request, response) => {
/** Image processing and send to s3 */
const urls = request.body;
urls.forEach(async url => {
await bufferConvertUtil
.buffer(url)
.then(buffer => {
return processHelperApp.image(buffer, url);
})
.then(data => {
console.log(data);
})
.catch(error => {
console.log('errr ' + error);
fs.appendFile('log.txt', `"${url}",\n`, (err, data) => {
if (err) console.log(err);
});
});
});
responseUtil.success(response, 'done');
};
I need to add new request into queue using kue or rabbitmq library. Once one queue is finished then processing then process next request.
The best way to do this is using a native for loop and awaiting for all your processes. Like so:
function addErrorToLog(url) {
return new Promise((resolve, reject) => {
fs.appendFile('log.txt', `"${url}",\n`, (err, data) => {
if (err) console.log(err);
resolve(err || data);
});
});
}
exports['v1'] = async (request, response) => {
/** Image processing and send to s3 */
const urls = request.body;
for (let i = 0; i < urls.length; i++) {
try {
const url = urls[i];
const buffer = await bufferConvertUtil
.buffer(url)
const data = await processHelperApp.image(buffer, url);
console.log(data);
} catch (error) {
console.log('errr ' + error);
await addErrorToLog(url);
}
}
responseUtil.success(response, 'done');
};
This way you can wait until one operation finishes to process the next, and I put the error log to a separate function so it is easier for you to change the code without changing the structure.
Hope to have helped!
Finally I have done this by the kue library. Its very simple, anyway see my code
`
const kue = require('kue')
const queue = kue.createQueue();
exports['v1'] = (request, response) => {
// This is to push the data
queue.create('key_name', {
your_key: your_val
})
// do the stuff the queue data
queue.process('key_name', (job, done())=>{
your_task_funtion(job.data, cb) // job.data will fetch your data witch you have stored into the queue
})
}
`

How to do error handling with async/await without having to await

Take the following contrived example:
const housekeepingStuff = async function (data) {
const result = await notImportant(data);
result.more = 'yawn';
storeInDatabase(result);
};
const getStuff = async function () {
try {
const data = await getData();
data.extra = 'wow';
housekeepingStuff(data); // <---- don't want to await... but need to for error catching
return Promise.resolve(data);
} catch (err) {
return Promise.reject(err);
}
};
try {
const myData = await doSomeStuff();
res.send(myData);
} catch (err) {
console.log(err);
res.sendStatus(400);
}
I want to return the data from getStuff () ASAP without waiting for housekeepingStuff() but if I don't await that function then I have an uncaught error.
I could call housekeepingStuff() outside the getStuff() function, after getting and sending the data to whoever wants it:
try {
const myData = await doSomeStuff();
res.send(myData);
await housekeepingStuff(data); // <---- am awaiting but who cares because nothing follows
} catch (err) {
console.log(err);
res.sendStatus(400);
}
But that doesn't seem right because I don't want to have to remember to call housekeepingStuff() every time I call doSomeStuff()... it should ideally be handled "internally".
What is the correct approach here?
A promise (or async) function has 2 possible outcomes:
A successful outcome
An error outcome
To get either outcome, you must wait for it. You can't wait for 1 condition and not for the other, because the entire thing needs to execute so you can find out what the outcome was.
Otherwise you're really asking the javascript engine: Please predict for me if the function will fail, and if it does, await it.
The correct approach therefore is to just await it.
However, if you don't care about either successful or failed outcomes of this function, just call the function via another async function that eats all the errors:
async function doSomeStuffAndIgnoreError() {
try {
await doSomeStuff();
} catch (e) {
console.error(e);
}
}

socket.emit and wait until user response after that resolve promise

I am writing web app which controls hardware. I have a server communicated with the device through the serial port. Everything works except the interaction with a user. The device has registers which I repeatedly ask waiting for some values. If some values come, I emit an event to the client and confirmation box appears. The user selects resume or abort. After that client emit the response (true or false) and I would like to resolve this response in my promise function. I need to catch response from the user exactly in the function because I have a sequence of actions I need to proceed. Promise after promise. It seems that my function ends before the user answers. How to solve this problem?
this is my code on the server:
waitUserResponse(message) {
return new Promise(async (resolve) => {
const handler = function(data) {
console.log('userAnswer = ', data);
resolve(data);
return;
}
this.io.sockets.emit('alerts', message);
this.io.sockets.once('userAnswer', handler);
})
}
this is my code on the client:
componentDidMount() {
const confirmDialog = (msg) => {
return new Promise((resolve) => {
let confirmed = window.confirm(msg);
resolve(confirmed);
return;
})
}
socket.on('alerts', data => {
confirmDialog(data).then(data => {
console.log(data);
socket.emit('userAnswer', data);
});
});
}
I should use socket.id - id for my connection
io.sockets.connected[socket.id].once('userResponce', handler);

Categories