Python에서 스케쥴 잡을 수행할 수 있는 라이브러리를 테스트하고 내용을 정리합니다.
ㅇ 참고 포트스 : https://jackerlab.com/python-library-schedule
위 포스트에서 스케쥴 잡을 수행할 수 있는 Python 라이브러리 schedule에 대한 내용을 정리해 보았습니다.
이 내용을 바탕으로 실제 라이브러리를 이용하여 코드를 테스트해보고 실제 동작 결과를 확인해 보도록 하겠습니다.
테스트
Job 등록
# 코드
import schedule
from pprint import pprint
def job1():
print("run Job 111")
def job2():
print("run Job 222")
def tag():
print("run Job 333")
# 10초에 한번씩 실행
schedule.every(1).seconds.do(job1)
# 10분에 한번씩 실행
schedule.every(10).minutes.do(job2)
# 매 시간 실행
schedule.every().hour.do(job1)
# 매일 10:30 에 실행
schedule.every().day.at("10:30").do(job2)
# 매주 월요일 실행
schedule.every().monday.do(job1)
# 매주 수요일 13:15 에 실행
schedule.every().wednesday.at("13:15").do(job2)
# # tag('test')를 붙인 Job 등록
# schedule.every().wednesday.at("13:15").do(tag).tag('test')
schejule.every().xxx.do(job)을 사용하여 원하는 주기 혹은 시점에 job이 수행되도록 등록할 수 있습니다.
위 Job 등록 코드를 여러번 실행하면 중복으로 Job이 누적하여 등록이 됩니다.
등록된 Job 확인
# 코드
from pprint import pprint
print("Job 확인")
pprint(schedule.jobs)
# 결과
Job 확인
[Every 1 second do job1() (last run: [never], next run: 2019-09-04 21:40:49),
Every 10 minutes do job2() (last run: [never], next run: 2019-09-04 21:50:48),
Every 1 hour do job1() (last run: [never], next run: 2019-09-04 22:40:48),
Every 1 day at 10:30:00 do job2() (last run: [never], next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: [never], next run: 2019-09-09 21:40:48),
Every 1 week at 13:15:00 do job2() (last run: [never], next run: 2019-09-11 13:15:00),
Every 1 week at 13:15:00 do tag() (last run: [never], next run: 2019-09-11 13:15:00)]
schedule.jobs 변수로 현재 등록된 Job 리스트를 확인 할 수 있습니다.
설정된 주기 혹은 시점과 수행되는 Job을 출력하고 마지막 Job 수행 계획(날짜)과 다음 수행 계획(날짜)을 알려줍니다.
등록된 전체 Job 삭제
# 코드
print("Job 확인")
pprint(schedule.jobs)
schedule.clear()
print("Job 삭제 확인")
pprint(schedule.jobs)
# 결과
Job 확인
[Every 1 second do job1() (last run: [never], next run: 2019-09-04 21:40:49),
Every 10 minutes do job2() (last run: [never], next run: 2019-09-04 21:50:48),
Every 1 hour do job1() (last run: [never], next run: 2019-09-04 22:40:48),
Every 1 day at 10:30:00 do job2() (last run: [never], next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: [never], next run: 2019-09-09 21:40:48),
Every 1 week at 13:15:00 do job2() (last run: [never], next run: 2019-09-11 13:15:00),
Every 1 week at 13:15:00 do tag() (last run: [never], next run: 2019-09-11 13:15:00)]
Job 삭제 확인
[]
schedule.clear()를 이용하여 등록된 Job을 모두 삭제 할 수 있습니다.
tag를 이용하여 특정 tag의 Job만 삭제
# 코드
print("Job 확인")
pprint(schedule.jobs)
schedule.clear(tag='test')
print("Job 삭제 확인")
pprint(schedule.jobs)
# 결과
Job 확인
[Every 1 second do job1() (last run: [never], next run: 2019-09-04 21:26:27),
Every 10 minutes do job2() (last run: [never], next run: 2019-09-04 21:36:26),
Every 1 hour do job1() (last run: [never], next run: 2019-09-04 22:26:26),
Every 1 day at 10:30:00 do job2() (last run: [never], next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: [never], next run: 2019-09-09 21:26:26),
Every 1 week at 13:15:00 do job2() (last run: [never], next run: 2019-09-11 13:15:00),
Every 1 week at 13:15:00 do tag() (last run: [never], next run: 2019-09-11 13:15:00)]
Job 삭제 확인
[Every 1 second do job1() (last run: [never], next run: 2019-09-04 21:26:27),
Every 10 minutes do job2() (last run: [never], next run: 2019-09-04 21:36:26),
Every 1 hour do job1() (last run: [never], next run: 2019-09-04 22:26:26),
Every 1 day at 10:30:00 do job2() (last run: [never], next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: [never], next run: 2019-09-09 21:26:26),
Every 1 week at 13:15:00 do job2() (last run: [never], next run: 2019-09-11 13:15:00)]
Job 실행 – run_all()
# 코드
print("Job 확인")
pprint(schedule.jobs)
schedule.run_all()
print("Job 수행 확인")
pprint(schedule.jobs)
# 결과
Job 확인
[Every 1 second do job1() (last run: [never], next run: 2019-09-04 21:40:49),
Every 10 minutes do job2() (last run: [never], next run: 2019-09-04 21:50:48),
Every 1 hour do job1() (last run: [never], next run: 2019-09-04 22:40:48),
Every 1 day at 10:30:00 do job2() (last run: [never], next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: [never], next run: 2019-09-09 21:40:48),
Every 1 week at 13:15:00 do job2() (last run: [never], next run: 2019-09-11 13:15:00),
Every 1 week at 13:15:00 do tag() (last run: [never], next run: 2019-09-11 13:15:00)]
run Job 111
run Job 222
run Job 111
run Job 222
run Job 111
run Job 222
run Job 333
Job 수행 확인
[Every 1 second do job1() (last run: 2019-09-04 21:42:12, next run: 2019-09-04 21:42:13),
Every 10 minutes do job2() (last run: 2019-09-04 21:42:12, next run: 2019-09-04 21:52:12),
Every 1 hour do job1() (last run: 2019-09-04 21:42:12, next run: 2019-09-04 22:42:12),
Every 1 day at 10:30:00 do job2() (last run: 2019-09-04 21:42:12, next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: 2019-09-04 21:42:12, next run: 2019-09-09 21:42:12),
Every 1 week at 13:15:00 do job2() (last run: 2019-09-04 21:42:12, next run: 2019-09-11 13:15:00),
Every 1 week at 13:15:00 do tag() (last run: 2019-09-04 21:42:12, next run: 2019-09-11 13:15:00)]
예약된 Job 수행 일정에 상관없이 등록된 모든 Job이 1회 수행됩니다.
run_all()에 의해 1회 수행되었기 때문에 등록된 Job의 상태를 보면 last run 정보가 [never] –> 일괄 수행된 마지막 수행 일자로 변경되 것을 확인할 수 있습니다.
run_all(delay_seconds=0)를 이용한 테스트는 아래와 같습니다.
# 코드
print("Job 확인")
pprint(schedule.jobs)
schedule.run_all(delay_seconds=1)
print("Job 수행 확인")
pprint(schedule.jobs)
# 결과
Job 확인
[Every 1 second do job1() (last run: 2019-09-04 21:42:12, next run: 2019-09-04 21:42:13),
Every 10 minutes do job2() (last run: 2019-09-04 21:42:12, next run: 2019-09-04 21:52:12),
Every 1 hour do job1() (last run: 2019-09-04 21:42:12, next run: 2019-09-04 22:42:12),
Every 1 day at 10:30:00 do job2() (last run: 2019-09-04 21:42:12, next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: 2019-09-04 21:42:12, next run: 2019-09-09 21:42:12),
Every 1 week at 13:15:00 do job2() (last run: 2019-09-04 21:42:12, next run: 2019-09-11 13:15:00),
Every 1 week at 13:15:00 do tag() (last run: 2019-09-04 21:42:12, next run: 2019-09-11 13:15:00)]
run Job 111
run Job 222
run Job 111
run Job 222
run Job 111
run Job 222
run Job 333
Job 수행 확인
[Every 1 second do job1() (last run: 2019-09-04 21:45:11, next run: 2019-09-04 21:45:12),
Every 10 minutes do job2() (last run: 2019-09-04 21:45:12, next run: 2019-09-04 21:55:12),
Every 1 hour do job1() (last run: 2019-09-04 21:45:13, next run: 2019-09-04 22:45:13),
Every 1 day at 10:30:00 do job2() (last run: 2019-09-04 21:45:14, next run: 2019-09-05 10:30:00),
Every 1 week do job1() (last run: 2019-09-04 21:45:15, next run: 2019-09-09 21:45:15),
Every 1 week at 13:15:00 do job2() (last run: 2019-09-04 21:45:16, next run: 2019-09-11 13:15:00),
Every 1 week at 13:15:00 do tag() (last run: 2019-09-04 21:45:17, next run: 2019-09-11 13:15:00)]
일괄로 모든 Job을 수행하지만 설정한 seconds 만큼 작업간에 지연시간을 가지고 수행을 합니다.
Job 실행 – run_pending()
예약된 주기, 시점일 경우만 해당 Job이 수행되고 run_pending()이 호출될 때는 Job을 조회했을 때 확인할 수 있었던 next run 값을 참조하여 다음 수행 시간이 지났을 때에 해당되는 Job만 수행을 합니다.
그러므로 run_pending()의 경우는 1초에 1번씩 호출하여 예약된 Job의 스케쥴을 체크하는 것이 좋을 것 같습니다.
테스트를 원활하게 하기 위하여 스케쥴 등록의 주기를 짧게하여 비교해 보겠습니다.
# 코드
# Job 등록 1회
schedule.every(10).seconds.do(job1)
# 코드
# run_pending() 테스트
print("Job 확인")
pprint(schedule.jobs)
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
schedule.run_pending()
print("Job 수행 확인")
pprint(schedule.jobs)
# 결과 1 - 1회 수행 안됨
Job 확인
[Every 10 seconds do job1() (last run: 2019-09-04 22:03:47, next run: 2019-09-04 22:03:57)]
2019-09-04 22:03:49
Job 수행 확인
[Every 10 seconds do job1() (last run: 2019-09-04 22:03:47, next run: 2019-09-04 22:03:57)]
# 결과 2 - 2회 수행 안됨
Job 확인
[Every 10 seconds do job1() (last run: 2019-09-04 22:03:47, next run: 2019-09-04 22:03:57)]
2019-09-04 22:03:56
Job 수행 확인
[Every 10 seconds do job1() (last run: 2019-09-04 22:03:47, next run: 2019-09-04 22:03:57)]
# 결과 3 - 10초 지난 시간에 수행 됨
Job 확인
[Every 10 seconds do job1() (last run: 2019-09-04 22:03:47, next run: 2019-09-04 22:03:57)]
2019-09-04 22:04:04
run Job 111
Job 수행 확인
[Every 10 seconds do job1() (last run: 2019-09-04 22:04:04, next run: 2019-09-04 22:04:14)]
위 테스트 결과와 같이 next run 시간이 22:03:57이고 아직 이른 시간일 경우 Job이 수행되지 않았습니다.
그리고 next run 시간이 초과 하니 1회 Job을 수행하고 next run 시간이 갱신되는 것을 확인할 수 있었습니다.
그러므로 예약된 Job을 원하는 시점에 정확히 수행하기 위해서는 이전 포스트의 샘플코드와 같이 1초에 1회씩 run_pending()을 호출하여 Job을 체크하는 방식이 좋은 것 같습니다.
Job 잔여 시간 확인 – idle_seconds()
# 코드
# schedule.idle_seconds() 테스트
print("Job 확인")
pprint(schedule.jobs)
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
print(schedule.idle_seconds())
schedule.run_pending()
print("Job 수행 확인")
pprint(schedule.jobs)
# 결과 1 - 양수 시간
Job 확인
[Every 5 seconds do job1() (last run: 2019-09-04 22:34:20, next run: 2019-09-04 22:34:25)]
3.95478
Job 수행 확인
[Every 5 seconds do job1() (last run: 2019-09-04 22:34:20, next run: 2019-09-04 22:34:25)]
# 결과 2 - 음수 시간
Job 확인
[Every 5 seconds do job1() (last run: 2019-09-04 22:34:20, next run: 2019-09-04 22:34:25)]
-2.503744
run Job 111
Job 수행 확인
[Every 5 seconds do job1() (last run: 2019-09-04 22:34:27, next run: 2019-09-04 22:34:32)]
idle_seconds()를 이용하면 다음 Job 수행 계획(시간) 기준으로 현재 수행 시간과의 시간 차이를 확인할 수 있습니다.
양수시간은 다음 계획까지 남은 시간을 나타내고 음수시간은 수행 계획이 지난 시간을 의미합니다.
마치며
schedule 라이브러리에 대하여 테스트를 하고 결과를 확인하였습니다.
일부 테스트가 안되고 정리가 안된 부분이 있지만 여기까지 진행한 내용과 테스트 결과만 활용하더라도 원하는 스케쥴 잡을 만들고 실행 시킬 수 있을 것으로 생각됩니다.