R이든 파이썬이든 코드를 돌리다가 에러가 나는 경우가 많다. 코드가 정확하더라도 크롤링이나, 마크다운, 셀레늄 등의 작업은 응답속도 지연이나 알 수 없는 이유로 중단되는 경우가 있다.

특히 for나 while같은 루프 함수를 돌리다가 문제가 생기는 경우 상당히 일이 귀찮아 지는데 자동으로 코드를 다시 돌리는 함수를 미리 만들어 두면 상당히 유용하다.

여기서는 retry함수라고 명명하고 아래와 같은 함수를 만들어본다.

retry <- function(expr, isError=function(x) "try-error" %in% class(x), maxErrors=5, sleep=0) {
  attempts = 0
  retval = try(eval(expr))
  while (isError(retval)) {
    attempts = attempts + 1
    if (attempts >= maxErrors) {
      msg = sprintf("retry: too many retries [[%s]]", capture.output(str(retval)))
      flog.fatal(msg)
      stop(msg)
    } else {
      msg = sprintf("retry: error in attempt %i/%i [[%s]]", attempts, maxErrors, 
                    capture.output(str(retval)))
      flog.error(msg)
      warning(msg)
    }
    if (sleep > 0) Sys.sleep(sleep)
    retval = try(eval(expr))
  }
  return(retval)
}

사용방법은 아래와 같다.

retry(사용할 코드, maxErrors=10, sleep=2)
* maxErrors = 시도할 횟수
* sleep = 시도와 시도사이 쉬는 시간(단위: 초)

for (DEPARTMENT in unique(DATA$회사명)){
                                retry(rmarkdown::render("Report-Letter.Rmd", 
                                output_format = "pdf_document",
                                output_file = paste("report_", DEPARTMENT, ".pdf", sep=''),
                                encoding = "UTF-8"),
                                maxErrors=10, 
                                sleep=2)
}

예를 들어 위와 같은 코드를 만들었다고 치면 Report-Letter.Rmd파일을 PDF파일로 변경할 때 실패하게 되면 2초 간격으로 최대 10번 시도하게 되며 성공시 바로 다음 루프로 넘어가게 된다.

여기서 소개하는 함수 외에도 RETRY라는 함수가 있는데 해당 함수가 에러를 제대로 캐치하지 못하고 넘기는 경우가 있어서 웬만하면 retry함수를 만들어서 쓰는 중이다.

카테고리: IT

0개의 댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다