30

Have an application where I want to start a node express server and then start a browser on the same machine automatically as soon as the server is up. How can I query to see if the server is up and ready to go? I really wanted there to be some sort of callback on the .listen call, but doesn't seem to be. I could just wait a longer than I expect amount of time, but this is going on equipment that will be in the field so I either have to wait a ridiculous amount of time to make sure I'm up and running before kicking off the browser or have the user be smart enough to hit refresh if the page doesn't load right. Neither of those are good options for me. . .

I read the API online but don't see anything like this. Surely there's a trick I don't know that can accomplish this.

If the node HTTP api (which has a callback and tells me about the listening event) is the base for the express object, maybe there is a callback option for the express call listen that isn't documented. Or perhaps I'm supposed to just know that it's there.

Any help would be greatly appreciated.

Brian
  • 3,264
  • 4
  • 30
  • 43

6 Answers6

42

The Express app.listen function does support a callback. It maps the arguments that you pass in to the http.listen call.

app.listen = function(){
  var server = http.createServer(this);
  return server.listen.apply(server, arguments);
};

So you can just call: app.listen(port, callback);

Or you could use http.listen directly.

var app = require('express')(),
    server = require('http').createServer(app);

server.listen(80, function() {
    console.log('ready to go!');
});
Timothy Strimple
  • 22,920
  • 6
  • 69
  • 76
10

You can fire a custom event after the server is started:

// server.js
const express = require('express');
const app = express();

modeule.export = app;
app.listen(3000, () => {
   app.emit('listened', null)
});

In a separate module, the app can listen your custom event:

// custom.js
const server = require('server.js');
server.on('listened', function() {
  console.log('The server is running!');
});
Gergo
  • 2,190
  • 22
  • 24
  • This event will be emitted when the call to `listen` has been made but it doesn't indicate that the server is ready and listening. For that you should do something like: `app.listen(3000, () => app.emit('listened', null));` – DaveJ Feb 25 '16 at 00:45
  • @Daveyjoe You are right, thank you! I updated my answer. – Gergo Feb 25 '16 at 11:19
9

You can use the http.listen method which has a callback function that triggers once the server is ready:

http.createServer(app).listen(app.get('port'), function () {
    console.log('Printed when ready!!!');
});

See the official reference at Node.js:

http://nodejs.org/api/all.html#all_server_listen_port_hostname_backlog_callback

http://nodejs.org/api/all.html#all_server_listen_path_callback_1

http://nodejs.org/api/all.html#all_server_listen_handle_callback_1

knoxgon
  • 1,070
  • 2
  • 15
  • 31
Diosney
  • 10,520
  • 15
  • 66
  • 111
6

As many have mentioned, the listen function (on the express app or an http server, both support it), does support a callback and that will let your node process know when it is listening.

So if you plan to launch the browser from within your express app, do it there and you are good. However, if you are launching the express app from an external script and then want that external script to open the browser, the node callback doesn't really buy you anything.

Waiting for some magic string on stdout isn't really an improvement on just waiting for a good HTTP response. You may as well just use a try/backoff/timeout loop with curl until you get a successful response.

Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
6
server.on('listening', function() {
  resolve();//I added my own promise to help me await
});

The Listening event worked for me. Note I added my own Promise. I imagine you could obtain similar results without a promise by adding an entry point to this listener.

Note, I tried the more intuitive server.on('listen') and it didn't work. Running node 6.9.1

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
0

With async/await syntax, this can be done by wrapping the server startup in a promise, so you can wait for it to be started before running anything else:

import express from 'express';
import http from 'http';

const app = express();
let server: http.Server;
const startServer = async (): Promise<void> => {
  return new Promise((resolve, _reject) => {
    server = app.listen(3000, () => {
      console.log('Express server started');
      resolve();
    });
  });
};

await startServer();
// here the server is started and ready to accept requests
slhck
  • 36,575
  • 28
  • 148
  • 201