How to send email before process.exit() in NodeJS? - node.js

I need to send an email when server is shutting down, I'm using nodemailer but email is not sending when I write it before process.exit().
sendMail('Server is shutting down')
process.exit();
I was trying to use "beforeExit" event but it's not working either.
The 'beforeExit' event is not emitted for conditions causing explicit termination, such as calling process.exit() or uncaught exceptions.
As I understand as per the Doc.
Listener functions must only perform synchronous operations. The Node.js process will exit immediately after calling the 'exit' event listeners causing any additional work still queued in the event loop to be abandoned. In the following example, for instance, the timeout will never occur:
process.on('exit', (code) => {
setTimeout(() => {
console.log('This will not run');
}, 0);
});
On exit event it requires a sync call but nodemailer is async.

Node mail has a callback mechanism transporter.sendMail(data[, callback]), you can transfome that to a Promise
then you you will be able to do this in your code:
sendMail('Server is shutting down')
.then(()=>{
process.exit();
})
or you can add and await by transforming you function to an async function
as a results for one of the two solution process.exit(); will be called only after the sendMail function callback has excuted (=mail added to the queue of Postfix for example)

Related

Writing a custom winston-transport: why to emit logged event?

I'm working on a custom winston transport; documentation (cut&paste follows) is crystal clear...
class CustomTransport extends Transport {
log(info, callback) {
setImmediate(() => {
this.emit('logged', info);
});
// Perform the writing to the remote service
callback();
}
};
... but, which is the meaning of this.emit('logged', info); and why in a setImmediate?
I would have said that calling the callback was enough to let the caller know that writing operation have been performed,
we could say that setImmediate is required to fire the event after IO handlers in Node.js event loop, but there is absolutely no guarantee that next IO loop is enough for my custom write to be finished, so
why to fire something called 'logged' actually before the write operation rather than fire something called 'logging'?
I asked the same thing to the maintainers, but the result was... tumbleweeds.
Can somebody revel me the secrets behind that mysterious event?
Tired by the silence I did a test with a custom winston transport which does not fire the logged event: I wrote 3GB logs with 30,000,000 logger.info calls and I had no problems, neither the application grown by a single byte of memory usage.
My conclusion is: firing that event is completely useless.
Transports can listen to the logged event.
const transport = new CustomTransport();
transport.on('logged', (info) => {
// Verification that log was called on your transport
console.log(`Logging! It's happening!`, info);
});
If no transports are listening to that event, then it's useless.
I would emit the event just in case anyone is listening.
I checked winston's roadmap and in version 3.3.0 the "logged" event will be emitted automatically by winston-transport.

What is the expected response from a function that handles an SQS event?

I have a AWS lambda function written in javascript using the node12 runtime. If I fail to process the message given in the sqs event, how do I tell the queue that I was unable to process the message and to leave the message in the queue?
Does it require an http response with status code like 200 for success or 500 for failure, or does the lambda need to throw an error to signal that it didn't process.
I can't find what response is expected in an sqs event handler function. What is the handler expected to return?
async function handler(event) {
try {
const body = event.Records[0].body;
// do some process
// what do I return if successful
} catch (err) {
// what do I return if my process wasn't successful
}
}
This simple answer is that you and throw an error and it will consider it failed. Of course then lambda retry logic starts to kick in, so you need to understand that as well. This page talks about error handling in lambda, and gives a pretty good breakdown of the different scenarios.

How to handle connection timeout in ZeroMQ.js properly?

Consider a Node.js application with few processes:
single main process sitting in the memory and working like a web server;
system user's commands that can be run through CLI and exit when they are done.
I want to implement something like IPC between main and CLI processes, and it seems that ZeroMQ bindings for Node.js is a quite good candidate for doing that. I've chosen 6.0.0-beta.4 version:
Version 6.0.0 (in beta) features a brand new API that solves many fundamental issues and is recommended for new projects.
Using Request/Reply I was able to achieve what I wanted: CLI process notifies the main process about some occurred event (and optionally receives some data as a response) and continues its execution. A problem I have right now is that my CLI process hangs if the main process is off (is not available). The command still has to be executed and exit without notifying the main process if it's unable to establish a connection to a socket.
Here is a simplified code snippet of my CLI running in asynchronous method:
const { Request } = require('zeromq');
async function notify() {
let parsedResponse;
try {
const message = { event: 'hello world' };
const socket = new Request({ connectTimeout: 500 });
socket.connect('tcp://127.0.0.1:33332');
await socket.send(JSON.stringify(message));
const response = await socket.receive();
parsedResponse = JSON.parse(response.toString());
}
catch (e) {
console.error(e);
}
return parsedResponse;
}
(async() => {
const response = await notify();
if (response) {
console.log(response);
}
else {
console.log('Nothing is received.');
}
})();
I set connectTimeout option but wonder how to use it. The docs state:
Sets how long to wait before timing-out a connect() system call. The connect() system call normally takes a long time before it returns a time out error. Setting this option allows the library to time out the call at an earlier interval.
Looking at connect one see that it's not asynchronous:
Connects to the socket at the given remote address and returns immediately. The connection will be made asynchronously in the background.
Ok, probably send method of the socket will wait for connection establishment and reject a promise on connection timeout...but nothing happens there. send method is executed and the code is stuck at resolving receive. It's waiting for reply from the main process that will never come. So the main question is: "How to use connectTimeout option to handle socket's connection timeout?" I found an answer to similar question related to C++ but it actually doesn't answer the question (or I can't understand it). Can't believe that this option is useless and that it was added to the API in order to nobody can't use it.
I also would be happy with some kind of a workaround, and found receiveTimeout option. Changing socket creation to
const socket = new Request({ receiveTimeout: 500 });
leads to the the rejection in receive method and the following output:
{ [Error: Socket temporarily unavailable] errno: 11, code: 'EAGAIN' }
Nothing is received.
Source code executed but the process doesn't exit in this case. Seems that some resources are busy and are not freed. When main process is on the line everything works fine, process exits and I have the following reply in output:
{ status: 'success' }
So another question is: "How to exit the process gracefully on rejecting receive method with receiveTimeout?". Calling process.exit() is not an option here!
P.S. My environment is:
Kubuntu 18.04.1;
Node 10.15.0;
ZeroMQ bindings are installed this way:
$ yarn add zeromq#6.0.0-beta.4 --zmq-shared
ZeroMQ decouples the socket connection mechanics from message delivery. As the documentation states connectTimeout only influences the timeout of the connect() system call and does not affect the timeouts of sending/receiving messages.
For example:
const zmq = require("zeromq")
async function run() {
const socket = new zmq.Dealer({connectTimeout: 2000})
socket.events.on("connect:retry", event => {
console.log(new Date(), event.type)
})
socket.connect("tcp://example.com:12345")
}
run()
The connect:retry event occurs every ~2 seconds:
> node test.js
2019-11-25T13:35:53.375Z connect:retry
2019-11-25T13:35:55.536Z connect:retry
2019-11-25T13:35:57.719Z connect:retry
If we change connectTimeout to 200 then you can see the event will occur much more frequently. The timeout is not the only thing influencing the delay between the events, but it should be clear that it happens much quicker.
> node test.js
2019-11-25T13:36:05.271Z connect:retry
2019-11-25T13:36:05.531Z connect:retry
2019-11-25T13:36:05.810Z connect:retry
Hope this clarifies the effect of connectTimeout.

NodeJS child_process or nextTick or setTimeout for long waiting task?

I have seen some questions about sending response immediately and run CPU intensive tasks.
My case is my node application depends on third party service responses so the process flow is
Node receives request and authenticates with third-party service
Send response to user after authentication
Do some tasks that needs responses from third party service
Save the results to database
In my case there is no CPU intensive tasks and no need to give results of additional tasks to the user but node needs to wait for responses from third-party service. I have to do multiple req/res to/from the third-party service after the authentication to complete the task.
How can I achieve this situation?
I have seen some workarounds with child_process, nextTick and setTimeOut.
Ultimately I want to send response immediately to user and do tasks related to that user.
Thanks in advance.
elsewhere in your code
function do_some_tasks() { //... }
// route function
(req, res) => {
// call some async task
do_some_tasks()
// if the above is doing some asynchronous task, next function should be called immediately without waiting, question is is it so?
res.send()
}
// if your do_some_tasks() is synchronous func, the you can do
// this function call will be put to queue and executed asynchronously
setImmediate(() => {
do_some_tasks()
})
// this will be called in the current iteration
res.send(something)
Just writing a very general code block here:
var do_some_tasks = (req, tp_response) => {
third_party_tasks(args, (err, result)=<{
//save to DB
});
}
var your_request_handler = (req,res) => {
third_party_auth(args, (tp_response)=>{
res.send();
//just do your tasks here
do_some_tasks(req, tp_response);
});
}

Gracefully shutdown in node.js/express with async jobs

I am trying to make gracefully shutdown in node.js using express 4.x http server.
Closing express server is easy but what worries me is that we have a lot of async jobs. Example of the flow :
Receive request
Do some stuff
Send response back to the client
In background continue to do some async stuff related to that request like making another request to some third part service
Receive response from third part service and save response to database etc.
Finish
So if I make my gracefully shutdown code like this :
process.on('SIGTERM', function () {
serverInstance.close(function(){
closeConnectionToDatabases(function(){
process.exit(0);
})
});
// shutdown anyway after some time
setTimeout(function(){
process.exit(0);
}, 8000);
});
How can I be sure that everything goes ok if SIGTERM has happened between first and second step in flow explained above? What about fourth, fifth and sixth step? Is there any nice way to handle this or it is just about manually watch to all requests going from your service in async way and wait for them?
Thanks,
Ivan
process.exit() will terminate node.js process immediately, without waiting for all aync tasks to finish.
If you want a truly graceful shutdown, you should close all resources (all open connections and file descriptors) manually, instead of calling process.exit(). In this case node.js will terminate immediately after finishing all pending async tasks.
So, just close all database connections and other i/o resources:
process.on('SIGTERM', function () {
serverInstance.close(function(){
closeConnectionToDatabases(function(){
// now node.js should close automatically
})
});
// shutdown anyway after some time
setTimeout(function(){
process.exit(0);
}, 8000);
});
Here's a better option:
Instead of using setTimeout to wait for all the async jobs to finish, we can create a new Promise, and resolve it when the async jobs are completed. Then after the promise is resolved, we can exit the process.
process.on('SIGTERM', () => {
new Promise((resolve) => {
serverInstance.close(async () => {
await closeConnectionToDatabases();
resolve();
});
}).then(() => process.exit(0))
});
Hope it helps you :)

Resources