node.js로 server 개발 프로젝트 생성 절차

프로젝트 폴더를 만들어 VS.Code에서 오픈 후 package.json 파일 생성을 위해 터미널에서 다음 명령을 실행한 뒤에 생성된 파일을 편집함

npm init -y

{
  "name": "tstServer",
  "version": "1.0.0",
  "description": "",
  "keywords": [],
  "author": "",
  "license": "ISC"
}

nodemon 설치를 위해 다음 명령 실행

npm i nodemon -D

babel.config.json 파일과 nodemon.json 파일을 생성하고 각각 다음 내용으로 입력

{
    "presets": [ "@babel/preset-env" ]
}
{
    "exec": "babel-node src/index.js"
}

babel 설치를 위해 다음 명령 실행

npm i @babel/core @babel/cli @babel/node @babel/preset-env -D

express 설치를 위해 다음 명령 실행

npm i express

필요할 경우 pug 설치를 위해 다음 명령 실행

npm i pug

package.json에 설치된 항목에 대한 종속성(Dependency)가 존재하는지 확인하고 다음처럼 scripts 속성을 추가(또는 변경)

{
  "name": "tstServer",

  ..

  "scripts": {
    "dev": "nodemon"
  },

  "devDependencies": {
    "@babel/cli": "^7.20.7",
    "@babel/core": "^7.20.7",
    "@babel/node": "^7.20.7",
    "@babel/preset-env": "^7.20.2",
    "nodemon": "^2.0.20"
  },
  "dependencies": {
    "express": "^4.18.2",
    "pug": "^3.0.2"
  }
}

src 폴더 만들어 주고 index.js 파일 생성하고 다음처럼 입력

import express from "express";

const app = express();


const port = 7777;
const handleListen = () => console.log(`Listening on http://localhost:${port}`)
app.listen(port, handleListen);

다음 명령을 실행하여 서버 실행하고 웹브라우저에서 http://localhost:7777/로 접속해서 확인

npm run dev

Node.js에서 독립적인 프로세스를 통한 연산 및 그 결과 얻기

독립적인 프로세스를 통해 얻는 장점은 여러 개의 CPU를 활용하여 보다 더 빠른 결과를 얻을 수 있다는 점인데, 단점은 CPU 간의 데이터 공유가 참조(Reference)가 아닌 복사(Copy)이므로 메모리 사용량이 2배가 된다는 점이다. 하지만 이러한 단점은 특정한 상황에서는 아무런 문제가 되지 않는 경우가 있으므로 Node.js에서 독립적인 프로세스를 이용한 연산은 매우 유용한 경우가 많다.

먼저 독립적인 프로세스에서 수행할 코드는 worker.js 파일에 다음처럼 작성한다.

const process = require("process");

function getSum(arr) {
    let sum = 0;
    arr.forEach(i => {  sum += i; });
    return sum;
}

process.on("message", (message) => {
    if(message.cmd === "sum") {
        process.send({ result: getSum(message.data) });
    }
});

getSum이라는 함수를 처리하며 다른 프로세스로부터 전달 받은 데이터(배열 형태) 안의 숫자 값들의 합계를 전달해 준다.

이 worker.js를 사용하는 소스는 다음과 같다.

const cp = require("child_process");
const worker = cp.fork("./worker.js");

function task(arr) {
    return new Promise((resolve, reject) => {
        function onMessage(message) {
            resolve(message.result);
            worker.removeListener("message", onMessage);
        }

        worker.addListener("message", onMessage);

        worker.send({ 
            cmd: "sum",
            data: arr
        });
    })
}

task([1,2,3,4,5,6,7,8,9,10])
    .then((result) => {
        console.log(result);
        worker.kill();
    })
    .catch(err => {
        console.log(err);
    });

4번 코드에서 독립적인 프로세스에서 수행된 결과를 얻기 위해 Promise API를 사용했다는 점. 20번 코드에서 Prmoise의 일반적인 처리를 위해 then, catch를 사용하여 정상적인 경우와 예외처리를 하고 있다는 점이 코드의 완결성을 느끼게 해준다.

Node.js에서 fork를 사용해 독립적인 프로세스를 통한 연산

이전에 아래의 포스트를 통해 Node.js에서 스레드를 사용해 연산을 처리한 글을 올렸습니다.

Node.js에서 Thread 사용

이번에는 별도의 독립적인 프로세스를 통한 연산 수행해 그 결과를 얻는 코드에 대해 정리합니다. 위의 글과 동일한 기능을 구현하며 Thread 대신 Process를 이용한다는 차이점만 있습니다./p>

서버에 대한 코드는 다음과 같습니다.

const express = require("express");
const app = express();

const { fork } = require("child_process");

app.get("/", (req, res) => {
    const child = fork("./task.js");
    
    child.send("start");

    child.on("message", (sum) => {
        res.send({sum: sum});
    })
});

app.listen(3000);

외부 프로세스에서 수행할 연산에 대한 코드는 task.js 파일에 정의되는데.. 아래와 같습니다.

process.on("message", (message) => {
    if(message === "start") {
        let total = 0;

        for(let i=0; i<10000000000; i++) {
            total++;
        }
        
        process.send(total);
    }
})

Node.js에서 PostgreSQL 연결

이 글은 아래의 포스트 내용에 대해 DBMS를 이용해 재작성되었습니다.

Node.js의 GET, POST 처리

위 글에 대해서 클라언트의 코드는 모두 동일하고 서버의 코드만 변경되었습니다. 서버에 대한 전체 코드는 다음과 같습니다.

const express = require("express");
const app = express();

const { Client } = require("pg");

const dbClient = new Client({
    user: "postgres",
    host: "localhost",
    database: "postgres",
    password: "****",
    port: 5432
});

dbClient.connect();

app.get("/names", (req, res) => {
    dbClient.query("SELECT name FROM names", (error, result) => {
        if(error) {
            res.sendStatus(500);
        } else {
            res.status(200).json(result.rows);
        }
    });    
});

app.get("/alias", (req, res) => {
    const name = req.query.name;

    dbClient.query(`SELECT alias FROM names WHERE name = '${name}'`, (error, result) => {
        if(error) {
            res.sendStatus(500);
        } else {
            res.status(200).json(result.rows);
        }
    });
});

app.use(express.json());

app.post("/add", (req, res) => {
    const item = req.body;

    if(item.name && item.alias) {
        dbClient.query(`INSERT INTO names (name, alias) VALUES ('${item.name}', '${item.alias}');`, 
            (error, result) => {
                if(result) {
                    console.log(`Changed Row Count ${result.rowCount}`);
                    res.sendStatus(200);
                } else {
                    res.sendStatus(500);           
                }
            }
        );
    } else {
         res.sendStatus(400);
    }    
});

app.use(express.static(__dirname + "/static"));
app.listen(3000);

위의 코드에서 만약 DBMS에 대한 Connection Pool을 도입하고자 한다면 4~12번 코드를 다음처럼 변경하기만 하면 됩니다.

const { Pool } = require("pg");

const dbClient = new Pool({
    user: "postgres",
    host: "localhost",
    database: "postgres",
    password: "3224",
    port: 5432
});