프로젝트 시작 계기

기존 API를 호출하여 주소변환 작업을 진행하고 있던 중 API를 수도 없이 호출하기 때문에 connection faild오류가 발생하게 되었다.

주소를 변환 작업 도중 connection faild 오류가 발생하면 해당 작업이 끝난 시점부터 파일 안의 내용을 지우고 다시 시작해야된다는 단점이 있었고 Open API를 호출하다 보니 매크로가 아님을 방지하기 위해서 sleep()을 발생시켜 딜레이를 발생시켜야만 했다.

결과물이 나오는데 걸리는 시간이 3일이나 걸리고, 파일 데이터를 삭제하고 다시 돌리는 번거로움까지 추가되어 개발을 진행하게 되었다.

하고자 하는 목표

간단한 x좌표와 y좌표가 있는 csv파일을 업로드 시키면 알아서 좌표로 변환 후 엑셀파일로 변환시켜주는 자동화 작업을 하고 싶음

사실상 대규모의 트래픽을 감당하고 있지 않기 때문에 (대략 20000~3000건의 데이터 처리) 카프카를 사용할 이유는 없다.

  • 환경 : docker, local(mac)
  • 사용 언어 : python, javascript
  • 사용 프레임워크 : Nodejs, Kafka
  • 데이터베이스 : postgresql/postgis

보안점 수정

첫 개발 당시에는 엑셀파일을 csv파일로 변환한 후 해당 토픽을 kafka에게 던지는 방식으로 설계가 되어있다.

하지만, 중간과정인 엑셀파일을 csv파일로 변환하는 작업을 지우고 해당 토픽을 kafka에게 던지는 방식으로 바꾸었다.

또한, 추가하면서 html파일을 추가하여 업로드를 진행시에 자동으로 kafka에게 토픽을 던지는 방식으로 바꾸었다.

수정된 producer 코드

const express = require('express')
const router = express.Router()
const multer = require('multer')
const { producer } = require('../../producer/producer')

const storage = multer.memoryStorage()
const upload = multer({ storage: storage })

const path = require('path')
const xlsx = require('xlsx')
const regex = /,{7,}/g

const topic = 'overspeed-detail-address'

const sendProcuder = async (topic, result, partitionIndex) => {
	await producer.send({
		topic: topic,
		messages: [
			{ value: JSON.stringify(result), partition: partitionIndex % 3 },
		],
	})
}

const sendData = async (rows, splitNum) => {
	const regx = ','
	for (let i = 0; i < rows.length / splitNum; i++) {

		const result = []
		for (let j = splitNum * i; j < splitNum * (i + 1); j++){
			try {
				if (rows[j] !== undefined) {
					const row = rows[j].split(regx)
					result.push(row)
				}
			} catch(error) {
				console.log(error)
			}
		}
		await sendProcuder(topic, result, i)
	}
}

function convertToCSV(files) {
	const workBook = xlsx.read(files, {type: 'buffer'})
	const sheetName = workBook.SheetNames[1]
	const ws = workBook.Sheets[sheetName]

	const csv = xlsx.utils.sheet_to_csv(ws)
	const csvLines = csv.replace(regex, '').trim()
  return csvLines
}

router.post('/', upload.single('APK.xlsx'), async (req, res, next) => {
	const regx = '\n'
	const splitNum = 100
	const files = req.file.buffer
  
  const csvLines = convertToCSV(files)
	const rows = csvLines.split(regx)
  rows.shift()
	
  sendData(rows, splitNum)
	
  res.send(files)
})

module.exports = router;

추가된 html 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>엑셀 파일 업로드</title>
</head>
<body>
    <div class="main-box">
        <form action="/readFile" method="post" enctype="multipart/form-data" class="upload-form">
            <div>
                <label for="">Files</label>
                <input type="file" name="APK.xlsx" multiple>
            </div>
            <input type="submit" value="submit">
        </form>
    </div>
</body>
</html>

해당 프로젝트에 보안점이 생기면 더 추가할 예정이다.

댓글남기기