DI Studio 나 Enterprise Guide 에서 직접 돌리면 정상인데, Platform Process Manager 로 스케줄해 돌리면 실패한다. 두 가지 양상이 있고 원인이 전혀 다르므로 먼저 갈라야 한다.
| 양상 | 뜻 |
|---|---|
| 배치가 실제로 실행되지 않거나 중간에 죽는다 | 실행 컨텍스트가 다르다 |
| 배치는 끝까지 정상으로 돌았는데 Flow 화면만 빨갛다 | 판정 기준 문제다 |
로그 마지막까지 정상적으로 찍혔고 결과 데이터도 제대로 나왔다면 두 번째다. 이 경우 SAS 코드를 아무리 고쳐도 소용이 없다.
DI 실행과 스케줄 실행은 계정 · 서버 컨텍스트 · 환경변수 · 경로 · 권한이 다르다. 자주 걸리는 순서대로 본다.
| 항목 | 내용 |
|---|---|
| 실행 계정 | 스케줄은 서비스 계정(sassrv 등)으로 돈다. 그 계정에 파일·DB 권한이 없으면 실패 |
| 서버 컨텍스트 | DI 는 Workspace Server, 스케줄은 Batch Server 또는 Grid. 라이브러리·포맷 카탈로그 정의가 같은지 확인 |
| 인증 도메인 | 라이브러리가 사용자 메타 계정으로만 붙게 돼 있으면 서비스 계정에는 자격증명이 없다. AuthDomain 에 로그인 정보를 등록하고 라이브러리에 매핑 |
| 경로 | 상대경로와 사용자 홈 경로는 배치에서 통하지 않는다. 절대경로·공유경로로 통일. Windows 라면 매핑 드라이브 대신 UNC |
| 자동호출 경로 | 배치 서버의 autoexec_usermods.sas · sasv9_usermods.cfg 에 SASAUTOS · FMTSEARCH 가 없으면 매크로·포맷을 못 찾는다 |
| ODBC · DSN | 사용자 DSN 만 있고 시스템 DSN 이 없거나, 비트 수가 다르다 |
| 인코딩 | 배치의 -ENCODING 이 다르면 한글 경로·데이터에서 깨진다 |
| 실행 노드 | Grid 라면 다른 호스트에서 돈다. 그 노드에 마운트가 없을 수 있다 |
무엇이 다른지는 배치 로그에 직접 찍어 보는 것이 가장 빠르다. 작업 앞머리에 넣는다.
options mprint mlogic symbolgen source2 msglevel=i fullstimer;
%put NOTE: USER=&SYSUSERID HOST=&SYSHOSTNAME;
%put NOTE: WORK=%sysfunc(getoption(work));
%put NOTE: SASAUTOS=%sysfunc(getoption(sasautos));
%put NOTE: FMTSEARCH=%sysfunc(getoption(fmtsearch));
여기서 USER 가 예상과 다르거나 SASAUTOS 가 비어 있으면 원인이 바로 드러난다.
Process Manager 는 두 가지로 성패를 판정한다. OS 종료코드와 로그 문자열 패턴이다. 둘 중 하나만 걸려도 빨갛게 표시된다.
SAS 는 경고만 있어도 SYSCC 에 4 를 남기고, 그 값이 OS 종료코드로 나갈 수 있다. Process Manager 는 0 이 아니면 실패로 본다.
배치 마지막에 종료코드를 정리한다. ENDSAS 문은 인자를 받지 않으므로 ABORT RETURN 을 쓴다.
%macro normalize_rc(allow_warning=Y);
%local rc;
%let rc = &syscc;
%if %upcase(&allow_warning) = Y and &rc <= 4 %then %let rc = 0;
%put NOTE: Final SYSCC=&syscc -> Exit RC=&rc.;
%if &rc = 0 %then %do;
%let syscc = 0;
%end;
%else %do;
abort return &rc;
%end;
%mend;
%normalize_rc(allow_warning=Y)
ABORT RETURN n 은 SAS 를 즉시 끝내고 n 을 OS 종료코드로 내보낸다. 정상 종료 경로에서는 SYSCC 를 0 으로 되돌려 두면 SAS 가 알아서 0 으로 끝난다.
로그 안의 error=0, TotalErrors=0, ErrorCount: 0 같은 문자열이 error 를 찾는 패턴에 걸려 실패로 잡힌다. 잘 돌던 배치가 어느 날부터 실패로 뜨는 전형적인 이유다 — 코드가 아니라 데이터나 하위 프로그램이 뱉는 로그 문구가 바뀐 것이다.
SMC 의 Plug-ins → Schedule Manager → Flows → (Flow) → (Job) → Properties 에서 오류·성공 패턴을 조정한다. 오류 패턴을 줄 머리의 ERROR: 만 잡도록 좁힌다.
(?i)^\s*ERROR:
성공 토큰을 함께 쓰면 더 확실하다. 배치 마지막에 고유한 문자열을 찍고, 그것을 성공 패턴으로 등록한다.
%put NOTE: JOB_SUCCESS_TOKEN;
버전에 따라 이 화면에 패턴 항목이 없을 수 있다. 그때는 래퍼 스크립트가 종료코드를 제대로 전달하도록 해 두고, 종료코드만으로 판정하게 둔다.
Job 이 실행하는 것은 대개 셸 스크립트다. 스크립트가 SAS 의 종료코드를 그대로 돌려주지 않으면 판정이 어긋난다.
#!/bin/bash
/sas/bin/sas -sysin /sas/jobs/myjob.sas -log /sas/logs/myjob.log
rc=$?
echo "SAS_EXIT=$rc"
exit $rc
마지막 줄이 exit $rc 여야 한다. echo 로 끝나면 echo 의 종료코드인 0 이 나가고, 실패가 성공으로 보고된다. 반대로 set -e 나 set -o pipefail 이 스크립트나 /etc/profile.d/ 에 들어 있으면 중간 명령 하나가 실패해도 전체가 실패로 끊긴다.
-log 가 가리키는 디렉터리가 사라지면 SAS 가 로그를 쓰지 못하고 비정상 종료코드로 끝난다. 배치는 "돌긴 돈 것처럼" 보이는데 판정만 실패인 상태가 된다. 디렉터리를 만들어 준 뒤에도 실패가 계속된다면 권한·SELinux 컨텍스트를 확인한다.
namei -mo /sas/logs
restorecon -Rv /sas/logs
코드를 바꾸지 않았는데 판정이 바뀌었다면 주변이 바뀐 것이다. 짧게 훑을 목록이다.
rpm -qa --last | head -20 # 최근 패키지 변경
grep -n "set -e\|pipefail" /etc/bashrc /etc/profile.d/*.sh # 셸 정책 변경
grep -R "/sas/logs" /etc/logrotate.d # 로그 회전이 실행 중 로그를 건드리는지
ls -ld /sas/logs && namei -mo /sas/logs # 로그 경로 권한
logrotate 가 실행 중인 로그 파일을 옮기면 SAS 가 쓰던 파일 핸들이 끊긴다. 같은 서버의 다른 Lev 는 멀쩡한데 하나만 실패한다면, 그 Lev 의 로그 경로나 래퍼 스크립트만 다르게 손댄 흔적이 있는지 본다.
SAS_EXIT=0 이 보이는가 → 래퍼가 종료코드를 제대로 넘기고 있다.Final SYSCC=... -> Exit RC=0 이 보이는가 → 경고가 실패로 나가지 않는다.(?i)^\s*ERROR: 로 좁혀져 있는가 → error=0 류에 걸리지 않는다.