본문 바로가기

기능과 기술

파이썬으로 내가 만든 로직을 스케줄링하기 - schedule

728x90

파이썬으로 나만의 로직을 만들었다면 이제 실행을 해야 합니다. 만드는 과정 중에는 IDE에서 실행하거나 command창에서 실행하면서 로직이 정상적으로 수행되는지 확인했을 겁니다. 여기서 중요한 부분은 본인이 직접 IDE에서 실행, command창에서 실행했다는 겁니다. 이렇게 액션을 취해서 이뤄지는 것을 트리거(Trigger)라고 표현합니다.

트리거 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

 

트리거 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 트리거(Trigger)는 다음 뜻으로 쓰인다. 기본 의미[편집] 트리거(Trigger)는 총의 방아쇠를 뜻하는 사격용어이다. 트리거(Trigger)는 어느 특정한 동작에 반응해 자동

ko.wikipedia.org

총을 설명하려는 것이 아니라 트리거를 설명하기 위해 총 이미지를 활용한 것입니다. 탕탕탕!!

오늘은 트리거 관점에서 사용자가 액션을 취하지 않고 미리 정해놓은 타이밍에 트리거가 발생하도록 해주는 schedule 모듈 활용에 대해 알아보겠습니다. 저도 익숙해지기 위해 노력하고 있지만 우선은 파이썬에서 그런 모듈이 있는지 찾아보는 것이 1번일 것입니다. 구글링 +_+

ChatGPT를 많이 활용하고 있지만 아직도 간단한 내용은 구글링이 더 빠르고 편한 경우가 많습니다~

훓터보니 schedule, apscheduler가 눈에 띕니다. 그러면 다음 단계로 각각의 github 리파지토리를 보면 판단이 될 것 같습니다.

schedule github
apscheduler github

흠.. 파이썬에서 스케줄링을 하기 위한 schedule과 apscheduler는 몇 가지 지표에서 schedule이 약간 앞서는 느낌입니다. 그러나 이 정도 차이는 큰 것 같진 않습니다. 그래도 하나를 결정해서 작업을 해야 해서 schedule을 선택했습니다. schedule 공식 사이트에 가봅니다.

schedule — schedule 1.2.0 documentation

 

schedule — schedule 1.2.0 documentation

 

schedule.readthedocs.io

상세하게 문서 정리가 잘 되어 있습니다. Example로 어떻게 동작하는지 빠르게 체험해본 후 내가 진짜 동작시키고 싶은 방법은 어떻게 할 수 있는지 상세하게 확인해 보면 될 것 같습니다.

pip install schedule

schedule을 사용하기 위해서 설치 해줍니다. 그리고 예제를 복붙으로 체크해 봅니다.

import schedule
import time

def job():
    print("I'm working...")

schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
schedule.every().day.at("12:42", "Europe/Amsterdam").do(job)
schedule.every().minute.at(":17").do(job)

while True:
    schedule.run_pending()
    time.sleep(1)

대충 봐도 job()을 스케줄링한다는 것을 알 수 있습니다.

  • 10분마다
  • 정각마다
  • 매일 10:30에
  • 월요일에
  • 수요일 13:15에
  • 매일 12:42에 (유럽/암스테르담 시간)
  • 매시 17분마다

요런 느낌이네요. 저는 매일 오전 8:30분에 제가 만든 로직을 실행하고 싶었고 이는 너무 심플하다 보니 바로 사용할 수 있었습니다.

schedule.every().day.at("08:30").do(job)

좀 더 많은 예제와 가능한 항목에 대한 확인은 Example 페이지를 참고해 주세요. 진짜 잘 정리가 되어있는 것 같습니다. +_+ 저도 기능을 만들 때 이렇게 설명할 수 있을 정도로 만들어야 할 텐데 너무 먼 일인 것 같습니다.

Examples — schedule 1.2.0 documentation

 

Examples — schedule 1.2.0 documentation

Examples Eager to get started? This page gives a good introduction to Schedule. It assumes you already have Schedule installed. If you do not, head over to Installation. Run a job every x minute import schedule import time def job(): print("I'm working..."

schedule.readthedocs.io

이제 특정 시간에 트리거를 사용자가 직접 걸지 않고 프로그램에서 해결할 수 있게 되었습니다. 그런데 뭔가 부족한 부분이 있긴 합니다. 찝찝한 느낌. 우선 schedule에서 알려주는 한계점에 대해 확인해 보겠습니다.

When not to use Schedule
Let’s be honest, Schedule is not a ‘one size fits all’ scheduling library. This library is designed to be a simple solution for simple scheduling problems. You should probably look somewhere else if you need:

  • Job persistence (remember schedule between restarts)
  • Exact timing (sub-second precision execution)
  • Concurrent execution (multiple threads)
  • Localization (workdays or holidays)

Schedule does not account for the time it takes for the job function to execute. To guarantee a stable execution schedule you need to move long-running jobs off the mainthread (where the scheduler runs). See Parallel execution for a sample implementation.

뭔가 한계점이 있긴 한데 제가 생각하는 좀 더 필요한 부분은 아래와 같습니다.

  • 스케줄링이 설정된 파일은 실행시켜줘야 한다.
  • 8시 30분에 실행되면 좋겠다고 생각했는데 10시 30분에 스케줄링 파일이 실행된다면? 오늘의 명령은 씹히는(?) 상태가 된다.

우선 스케줄링이 설정된 파일을 실행하는 것은 윈도 작업 스케줄러로 해결할 수 있습니다. 윈도우가 업데이트(?) 등으로 인해 재부팅 되더라도 작업 스케줄러를 통해 스케줄링이 설정된 .py 파일을 실행할 수 있습니다. 윈도우 작업 스케줄러로 등록하는 방법이 궁금하다면 댓글로 요청 주세요. 제가 작업해 본 내용을 간단히 설명드리겠습니다.

그런데 조금 늦게 재부팅이 되면서 예약한 스케줄이 씹히는 건 보완 로직으로 풀어야 합니다. 저는 대충 아래와 같이 풀었습니다.

import time
from datetime import datetime
import schedule
import main_collector


def collector_all():
    main_collector.main()


collector_all_setting = "08:30"

collector_all_time = datetime.strptime(collector_all_setting, "%H:%M").time()
now_time = datetime.now().time()

if collector_all_time < now_time:
    collector_all()

schedule.every().day.at(collector_all_setting).do(collector_all)

while True:
    schedule.run_pending()
    time.sleep(1)

8시 30분에 수행되었으면 하는 스케줄인데 실행 시점의 시간이 지났다면 강제로 실행을 한 번 합니다. 실행 시간이 긴 함수라서 추후에는 멀티스레딩 방식으로 풀어봐야겠네요. 매번 개선점이 눈에 보이다 보니 작업 진도가 잘 안 나가기도 하지만 조금씩 좋아진다는 점이 매우 긍정적입니다.

언제든지 궁금한 내용은 댓글로 남겨주세요. 최선을 다해서 답변드리겠습니다.
오늘 하루도 즐거운 하루였기를 바랍니다.

반응형