Web 프로그래밍을 하다가 보면 가끔 일정시간 또는 주기별로 어떤 작업을 자동으로 처리해야 하는 경우가 있습니다. 예를 들어 매 5분마다 특정 URL의 페이지를 자동으로 실행하여 DB를 업데이트 해야 하거나 하는 작업들 말이죠.. 이러한 작업스케쥴은 한번만 자동으로 실행하거나 또는 매일, 매주, 매월 또는 매 5분마다, 매 60초마다 처리해야 하는 경우가 있습니다.
일반적으로 Coldfusion(CFM)을 비롯하여 PHP, ASP, JSP와 같은 Script기반의 언어들은 자체적으로 실행될 수 없기 때문에 반드시 서버측에 해석기가 실행과 해석, 결과질의를 처리해 줍니다. 문제는 이러한 특성때문에 일정반복과 같은 단순한 작업에도 처리가 어려운 것이 사실입니다. Java나 .net과 같이 프로세스(데몬)을 직접 띄울 수 있는 언어야 간단한 실행프로그램을 제작하여 실행해 주면 그만이지만 대부분의 Web Script에서는 Linux에서는 Cron, Windows에서는 작업스케줄러에 등록하여 처리하기도 합니다.
하지만 이 경우도 비단 쉬운것만이 아닌 이유가 Linux의 경우 Cron을 실행할 Shell를 직접 Coding해야 하고, Cron tab에 등록해줘야 하며, Root권한으로 Cron Deamon을 재시작해줘야 하므로 웹호스팅 사용자는 이용할 수 없는 방법입니다. 물론 Windows의 경우도 마찬가지죠. Administrator권한이 아니고서는 작업스케쥴러에 작업을 등록하기 어렵습니다. 하지만 Coldfusion을 이용하면 이 문제는 매우 간단하게 해결됩니다. 대부분의 Coldfusion 호스팅이라도 각각의 웹호스팅별 웹관리자 모드를 제공하므로 간단히 작업을 등록해 주는 것만으로 원하는 모든 작업을 처리할 수 있습니다.
Adobe Coldfusion은 Oracle의 Weblogic, IBM Webshere, Sun Glassfish, Redhat Jboss, Caucho resin 등과 같은 WAS(Web Application Server)인 Adobe Jrun Server가 내장되어 있고, 또한 대부분의 WAS처럼 Web 관리자모드를 제공하며, DB의 연결, 클러스터링, 관리모니터링 등의 대부분의 기능을 제공하는 막강한 기능을 제공하고 있습니다. 그러나 Adobe Coldfusion 역시 무료가 아닌 상용서버이므로 그림의 떡이 될 수 있겠지만, Adobe Coldfusion의 대부분의 기능을 제공하는 Open Source Coldfusion 엔진인 Railo 역시 대부분의 WAS로서의 기능을 제공한다는 점에서 Schedule작업이 그리 어려운 작업이 아니란 점을 분명히 말씀드리고 싶습니다.
몇일전 제가 근무하는 회사에서 매3분마다 DB의 쿼리결과를 특정파일로 만드는 작업과 외부에서 올라오는 특정 텍스트 파일을 읽어 해석하고 다시 DB에 Insert하는 간단한 PHP코드를 만들어 Cron으로 구동한 결과 2시간만에 서버에 부하가 걸려 SSH접속조차 처리할 수 없을 정도로 과부하가 되는 경험을 하였습니다. 물론, 효과적이고 최적화된 Shell 스크립트가 아닐 수 있지만 일반적인 성능상으로 볼때 매우 실망적이고, 불안한 요소임을 부인할 수 없었습니다.
퇴근 후 집에서 Coldfusion으로 해당 작업과 비슷한 테스트용 cfml코드를 짜고, Railo를 이용하여 테스트한 결과 매우 안정적이였고, 서버의 부하정도는 검사가 불가능할 정도로 변화가 없었습니다. 그만큼 Java에 기반한 Coldfusion이기에 가능하지 않았나 봅니다. 그래서 아래의 몇가지 상황에 대하여 간단히 예제를 만들어 보는 시간을 갖어보았으면 합니다.
Railo Task Schedule를 이용한 회원 생일축하 Mail 자동으로 보내기 예제
우선, 회원정보가 저장되어 있는 특정 DB의 회원 Table에서 오늘의 생일을 검색하고 오늘 날짜가 회원의 생일과 동일한 경우 자동으로 생일축하 메일을 발송하는 시스템을 Coldfusion을 이용해서 만들어 보겠습니다. 회원관리를 하는 웹사이트의 경우 Marketing적인 측면에서 회원의 생일 챙기고, 메일을 보내준다면 분명 고객의 경우 기뻐하실 겁니다만, 회원수가 10만명 이상인 경우 관리자가 일일히 매일 특정시간에 오늘이 회원인 사람을 검색하여 수동으로 Mailing한다는 것은 분명 비효율적인 작업임에는 분명합니다.
여기서는 회원 table에 대한 내용에 대한 부분은 설명드리지 않고, 단지 Railo를 이용해서 작업을 등록하고, 매일 지정된 시간에 회원 Table에서 오늘 생일인 회원을 검색하고, 검색된 회원에게 메일을 발송하는 것만 다뤄보겠습니다. 몇가지 사전조건의 경우, 우선 회원 table의 회원 생일은 연도, 월, 일이 따로 저장되어 있고, Railo 관리자모드에서 SMTP는 이미 지정되어 있다고 가정합니다.
Coldfusion 엔진들은 Adobe Coldfusion이나, Railo나 또는 Open Bluedragon이나 Mail Server와 DB Server 및 DB는 웹관리자모드에서 미리 지정하여 실제 cfm페이지 작성시 매번 Mail Server나 DB Server에 연결하는 Code를 작성하지 않도록 높은 생산성을 보장해 줍니다. 특히 Mail의 경우 SMTP 뿐만 아니라 <cfpop>태그를 이용하여 몇줄의 코드로 외부 또는 내부의 POP서버에서 메일을 가져오는 웹메일을 만들 수 있습니다. (이 부분에 대하여서는 다음 Post에서 다뤄보겠습니다.)
1. Railo 웹관리자에서 Schedule 추가하기
Railo의 웹관리자에 로그인 한 후 "Scheduled Tasks" 메뉴를 선택합니다. 아래 그림과 같은 작업등록 관리자가 화면에 나타납니다.

각각의 항목에 다음과 같이 임의의 내용을 입력합니다.
Name : 작업스케쥴의 이름입니다. 임의의 이름을 지정하면 됩니다. 여기서는 birthDay_mailing이라고 지정했습니다.
URL : 작업시 실행할 cfm파일이 있는 경로를 지정합니다. HTTP를 이용하므로 http://도메인/실행할파일.cfm 과 같이 절대 URL주소를 입력합니다. 여기서는 http://도메인/birthday_mailing.cfm 지정.
Interval Type : 작업일정간격을 지정합니다. 한번만, 매일, 매주, 매분 등의 간격을 지정합니다. 여기서는 매일 회원정보를 조회하고 메일을 발송하므로 Daily를 선택.
Start Date & Start Time : 이 작업스케쥴이 시작할 날짜입니다. 지금부터라면 자동으로 현재의 시간정보가 입력되어 나타납니다. 단, 작업스케쥴은 오늘 등록하지만 다음주 부터 실핼하려면 원하는 날짜를 입력하면 그 시점부터 작업을 진행합니다.
이제 Create 버튼을 누르면 보다 상세한 작업스케쥴 등록을 위한 Form이 나옵니다. 아래의 그림을 참고하세요. 각각의 항목에 대한 내용은 다음과 같습니다.


Name, URL은 앞선 화면에서 지정한 내용이 기본적으로 나타납니다.
Port : 기본적으로 URL의 주소로 접근가능한 Port를 지정합니다. 일반적으로 웹포트는 80이므로 자동으로 80이 지정됩니다. 실행할 cfm파일의 웹서버가 특정 Port로 지정되어 있다면 해당 Port로 변경합니다.
Timeout : URL로의 Requet timeout시간입니다. Railo는 기본적으로 특정 웹요청에 대한 처리시간이 50초로 지정되어 있습니다. 50초이상 서버에서 응답이 없으면 Connection을 끊고 서버는 대기상태로 되돌아 갑니다. 서버의 안정성을 위한 조치입니다. 여기서는 기본값인 50초로 지정합니다.
Username & Password : URL로 지정한 cfm파일은 일반적으로 웹루트 하위에 저장되어 있어 직접 브라우저의 주소창으로 입력하여 cfm파일을 실행할 수 있는 보안적인 문제가 발생합니다. 따라서 아이디/패스워드를 임으로 지정해 두면 누군가가 해당 URL로 접근한다 하더라도 아이디와 패스워드를 입력해야만 실행할 수 있도록 보안처리해 줍니다. 임의의 아이디와 패스워들 지정하세요.

Proxy Settings는 Proxy Server를 이용하는 경우 해당 Proxy Server를 지정하는 곳입니다. 여기서는 실행할 cfm파일이 Localhost에 있으므로 이 부분의 기재사항은 모두 공란으로 비워둡니다.

Output 항목은 처리결과를 특정 파일로 저장할 때 사용합니다. 예를 들어 File항목에 /home/output/결과.txt와 같이 지정한다면 보낸메일의 모든 내용이 결과.txt파일로 서버상에 저장됩니다. 처리결과, Log를 작성하는데 매우 유용한 기능입니다. 예를 들면, DB상의 어떤 정보를 select하여, txt파일로 서버상에 저장하여, FTP로 외부의 프로그램에서 다운로드 하거나, 또는 다른 서버상의 cfm파일에서 읽어다가 처리할 수 있는 기능도 만들 수 있습니다. Publish항목을 Check하면 결과.txt파일을 매번 만들지 않고, 내용의 맨 마지막에 추가정보를 계속 업데이트하여 파일로 저장해 줍니다.

자, 이제 마지막 제일 중요한 부분을 마지막으로 설정할 차례입니다. 작업스케쥴의 실행옵션은 Once(한번만), Daily(매일), Weekly(매주), Monthly(매월)로 간단히 지정할 수 있으며, 매분, 매초와 같은 경우는 마지막의 Every항목을 선택합니다. 선택 후 아래의 옵션을 지정하기면 하면 됩니다.
Start Date & Time : 앞선 화면에서 지정한 시작일자와 시간입니다.
End Date & Time : 이 작업이 완료되어 더이상 실행되지 않을 날짜와 시간입니다. 계속해서 반복해야 하는 일정에는 이 부분을 공란으로 비워두어야 합니다.
Interval : 매일, 매주, 매월, 한번만 항목이 아닌 Every항목을 선택하면, 매시간, 매분, 매초 마다 반복할 시간을 입력합니다. Hours 항목이 1이고, Minute항목이 4이며, Seconds항목이 32라면 이 작업은 매 1시간4분32초마다 반복된다는 의미입니다. 단, Hours, Minutes항목이 0이면 Seconds는 60이하로 지정할 수 없습니다. 이는 서버의 부하를 막기 위한 조치이며, 사실상 매30초마다 어떤작업을 반복한다는 것은 서버에 무한한 부하를 주는 행위입니다.
이제, 모든 작업설정이 끝났습니다. Update를 눌러 등록을 마친 후 Scheduled Tasks 메인화면에서 방금만든 작업을 선택한 후 Excute를 눌러 작업을 시작해 줍니다.
2. 작업스케쥴에서 실행할 Coldfusion 파일 만들기
예제의 조건에서 우리는 매일 회원DB의 Table에서 회원의 생일을 검색하고, 오늘날짜가 생일인 사람들을 검색하여, 자동으로 축하메일을 보내는 프로그램을 만든다고 했습니다. 이러한 과정을 cfml로 작성하면 다음과 같습니다. 물론, 보다 유연하고, 보내는 메일의 내용을 보다 예쁘게 작성할 수 있지만 여기서는 간단히 텍스트로 보내봅시다.
<cfquery name="CheckUser" datasource="mysqlDSN">
SELECT userid, username, email
FROM member
WHERE birth_month = #DateFormat(Now(), "mm")# AND birth_day = #DateFormat(Now(), "dd")#
ORDER BY userid DESC
</cfquery>
<cfloop query="CheckUser">
<cfmail from="Sender@Sender.com" to="#CheckUser.email#" subject="생일 축하 드립니다.">
#DateFormat(Now(), "mm")#월
#DateFormat(Now(), "dd")#일이 생일인
#CheckUser.username#고객님 !!
생신을 진심으로 축하드립니다. 감사합니다.
</cfmail>
</cfloop>
<cfquery> ~ </cfquery>부분은 Database에 쿼리를 날리고, 그 결과값을 받아오는 구문입니다. Coldfusion은 DB에 대한 연결을 DSN(Data Source Name)이라는 것으로 미리 웹관리자에서 정의합니다. 예를 들어 localhost의 Mysql의 Member DB에 대한 연결이름을 mysqlDSN이라고 정의했다면 위 첫번째 줄과 같이 datasource항목에 해당 DSN이름만 지정해 주면 PHP처럼 따로 DB연결하는 구문을 작성하지 않아도 알아서 DB에 연결해 줍니다.
SELECT 구문은 member Table에서 userid(아이디), username(회원이름), email(회원이메일) 항목을 검색해오는데, birth_month(생일의 달)과 birth_day(생일의 날짜)가 각각 오늘 일자인 경우만 검색하라는 SQL구문입니다. Now()함수는 오늘날짜와 시간을 구해오는 Coldfusion함수입니다. 이것을 mm 즉, 01~12와 같은 월수로 표현하도록 DateFormat 함수로 지정한 것이며, 일자 역시 같은 코드입니다. 이러한 검색결과를 첫번째 줄 name항목에서 지정한 CheckUser라는 임시 변수에 담아두고, <cfloop> ~ </cfloop>항목에서 그 결과값에 따라서 반복처리합니다.
<cfloop>태그는 반복태그입니다. <cfloop query="">부분은 위 <cfquery> ~ </cfquery>의 name 변수를 반복합니다. <cfmail> ~ </cfmail>부분은 메일을 발송하는 부분으로서 <cfmail>태그는 PHP의 mail()함수처럼 실제 메일을 발송하는 태그입니다. <cfmail의 from항목은 발송자의 메일주소를 지정하며, to항목은 실제 회원의 메일항목이므로 #CheckUser.email#처럼 Select 쿼리의 회원이메일을 동적으로 지정해줍니다. subject는 메일의 제목입니다. 그 이하의 내용은 메일의 본문에 해당됩니다. 보내는메일서버는 Railo와 같은 Coldfusion 엔진의 웹관리자에서 미리 지정해 두었으므로 알아서 해당 SMTP를 통하여 메일을 발송합니다.
이처럼 Coldfusion의 Code는 PHP, ASP, JSP등과 비교하여 놀랄정도로 코드작성량을 줄여주며, 매우 간결하며, 구조화된 Code작성이 강점입니다. 자주쓰는 태그와 함수를 몇개 외운다면 즉시 원하는 어플리케이션의 작성이 가능한 유일한 언어라고 감히 말씀드릴 수 있겠습니다.
자, 간단하게 나마, Railo에서의 Schedule를 이용하여 예제를 작성해 보았습니다. Adobe의 Coldfusion, Opn Bluedragon과 같은 다른 엔진에서도 동일한 기능을 제공하고 있으므로 쉽게 적용할 수 있습니다. 물론, 실행할 cfm파일은 위 소스를 전혀 변경하지 않고 모든 엔진에서 사용가능합니다. 끝까지 읽어 주셔서 감사합니다. 궁금증은 댓글로 남겨주세요.