본문으로 바로가기

node.js - DB 연동 이미지 파일 다운로드 스케줄링

category 코딩/node.js 2020. 7. 13. 11:15

 

아래와 같은 조건에서 이미지 파일들을 주기적으로 다운로드 받는다.

  1. 이미지 파일들의 정보는 DB에 저장되어 있다.
  2. 이미지 파일의 확장자는 미리 알 수 없다.
  3. 새롭게 업데이트(업로드)된 파일만 다운로드 받는다.

 

테이블 구조
mysql> SELECT SKU_CODE, img_lmdt FROM goods LIMIT 5;
+---------------+---------------------+
| SKU_CODE      | img_lmdt            |
+---------------+---------------------+
| 8000105005896 | 2019-04-19 11:31:56 |
| 8000105005902 | 2019-04-12 13:00:07 |
| 8000105005919 | 0000-00-00 00:00:00 |
| 8000105005926 | 2019-07-23 09:38:47 |
| 8000105005933 | 0000-00-00 00:00:00 |
+---------------+---------------------+

파일명은 상품 바코드인데 확장자는 알 수 없다. 다운로드 받은 이력이 있다면 변경일시가 기록되어 있다.

 

모듈 설치
npm install request
npm install fs
npm install moment
npm install mysql
npm install node-schedule
npm install forever -g

 

모듈 로드 등 기본 설정
var request = require('request');
var fs = require('fs');
var moment = require('moment');
const mysql = require('mysql');
const schedule = require('node-schedule');

var exts = ['png', 'jpg', 'PNG', 'JPG'];
var url = 'https://도메인.co.kr/';

const conn = {
    host: '127.0.0.1',
    port: '3306',
    user: '아이디',
    password: '비번',
    database: '디비'
};

var connection = mysql.createConnection(conn);
connection.connect();

var query = "SELECT SKU_CODE, img_lmdt FROM goods LIMIT 5";

connection.query(query, function (err, rows, fields) {

    if (err) {

        console.log(err);

    } else {

        for (var i = 0; i < rows.length; i++) {
        
        	// 이미지가 업데이트되었다면
            // - 새로 다운로드한다.
            // - 이번에 다운로드한 이미지의 파일 변경일시를 DB에 기록한다.
        
        }

    }

});

 

이미지 다운로드 로직
			// 미리 배열로 선언한 확장자만큼 시도
			exts.forEach(function (ext) {

                var image = rows[i].SKU_CODE;
                var lmdt = rows[i].img_lmdt;

                var options = {
                    method: 'GET',
                    uri: url + image + '.' + ext,
                    headers: { 'User-Agent': 'Mozilla/5.0' },
                    encoding: null
                };
                
                request(options, function(err, res, body) {
        
        			// request하는 URL에 이미지 파일이 존재한다면 헤더가 image/??? 형식이다.
                    // 이미지 파일이 아니거나 유효한 URL이 아니라면 text/??? 형식.
                    if (res.headers['content-type'].substring(0, 5) == 'image') {
        
        				// 헤더로부터 파일의 변경일시를 알 수 있다.
                        var modified = moment(res.headers['last-modified']).format('YYYY-MM-DD hh:mm:ss');
        
        				// DB에 기록된(마지막으로 다운로드 받은) 파일보다 최신이면 다시 다운로드한다.
                        if (lmdt < modified) {
        
                            request(options).pipe(fs.createWriteStream(image + '.' + ext));
                            connection.query("UPDATE goods SET img_lmdt = '" + modified + "' WHERE SKU_CODE = '" + image +"'");
        
                        }
        
                    }
        
                })
        
            });

 

스케줄링 등록

리눅스 서버라면 cron에 등록하여 주기적으로 실행되도록 스케줄링 설정을 할 수 있다.

물론 node.js 만으로도 가능하다.

 

// ...(생략)...
const conn = {
    host: '127.0.0.1',
    port: '3306',
    user: '아이디',
    password: '비번',
    database: '디비'
};

// 매일 새벽 2시에 실행하도록 설정
const job = schedule.scheduleJob('0 0 2 * * *', function() {

    var connection = mysql.createConnection(conn);
    connection.connect();

    var query = "SELECT SKU_CODE, img_lmdt FROM goods LIMIT 5";

    connection.query(query, function (err, rows, fields) {
// ...(생략)...
	});

});

 

이제 실행만 시키면 되는데, node download_image.js & 이렇게 백그라운드로 실행을 시켰다가는 서버 재부팅 등 예기치 못한 종료 후 다시 실행되지 않으므로 위에서 미리 설치한 모듈 forever 로 실행한다.

 

터미널에서

forever start download_image.js

list 로 forever가 실행 중인 process ID 를 확인 가능하고 해당 ID로 종료 stop 할 수 있다.

forever list
forever stop 0