October 19, 2023

Корректная остановка сервера.

При остановке сервера на Windows из подсистемы Linux нажатием Ctrl-Z повторный запуск скрипта не работает. Порт не занят, но скрипт запускается только при смене порта, приходится менять.

Поэтому, останавливаем сервер гуманным способом:

const express = require('express');
const readline = require('readline');

const app = express();
// Ваш остальной код сервера

// Ожидание команды из консоли для выключения сервера
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.on('SIGINT', function () {
  console.log('Сервер остановлен');
  process.exit();
});

// Запуск сервера
const port = 3003;
app.listen(port, function() {
  console.log(`Сервер запущен на порту ${port}`);
});

Here's an example of how you can create a Node.js server with secure shutdown functionality.

First, let's create a new directory for our project and navigate into it:

```sh
mkdir server-shutdown
cd server-shutdown
```

Next, let's initialize a new Node.js project with `npm init` and install the required dependencies:

```sh
npm init -y
npm install express --save
npm install dotenv --save
npm install nodemon --save-dev
```

Create a new file called `.env` in the root directory of your project and add the following lines:

```sh
PORT=3000
```

Create a new file called `index.js` and add the following code:

```js
require('dotenv').config();
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const graceful = require('graceful-shutdown');
const gracefulTimeout = 5 * 60 * 1000; // 5 minutes

// Set up middleware
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

// Define routes
app.get('/', (req, res) => {
res.send('Welcome to my Node.js server!');
});

// Start the server
const server = app.listen(port, () => {
console.log(`Server started on port ${port}`);
});

// Graceful shutdown
graceful(server, {
stop() {
return new Promise((resolve, reject) => {
console.log('Stopping server...');
server.close(() => {
console.log('Server stopped');
resolve();
});
});
},
timeout: gracefulTimeout,
});

// Handle SIGINT (Ctrl + C)
process.on('SIGINT', () => {
console.log('Received SIGINT (Ctrl + C). Stopping server...');
graceful.stop();
});

// Handle SIGTERM
process.on('SIGTERM', () => {
console.log('Received SIGTERM. Stopping server...');
graceful.stop();
});

// Handle uncaught exceptions
process.on('unhandledRejection', (reason, p) => {
console.error('Unhandled Rejection at Promise:', p, 'reason:', reason);
// Stop the server on uncaught exceptions
graceful.stop();
});
```

Let's break down what's happening in this code:

1. We require `dotenv` and `express` and initialize the application.
2. We set up the server on the specified port (`PORT` from `.env`) or default to `3000`.
3. We import `graceful-shutdown` and set up the graceful shutdown functionality.
4. We define a route for the homepage.
5. We start the server and log a message to the console.
6. We set up the graceful shutdown functionality. This function takes a server object and a configuration object. The configuration object has two properties: `stop` and `timeout`. The `stop` function is called when we want to gracefully stop the server, and it should return a promise that resolves when the server is stopped. The `timeout` property specifies the timeout in milliseconds before the server is forcefully stopped.
7. We handle the `SIGINT` (Ctrl + C) and `SIGTERM` signals and call the `stop` function from `graceful`.
8. We handle uncaught exceptions and call the `stop` function from `graceful`.

Now, run the server using `npm start` and test it by visiting `http://localhost:3000`. To gracefully stop the server, press Ctrl + C in the console. The server will log a message indicating that it's stopping and will close gracefully within the specified timeout. If the server is not stopped gracefully, it will be forcefully stopped after the timeout.

This implementation provides a secure and graceful way to stop the server, preventing any potential data loss or corruption.