如何提前退出/终止作业并在apscheduler中处理引发的异常?

时间:2017-10-20 12:01:44

标签: python apscheduler

我有一个阻止调度程序启动3个作业,没什么特别的。问题是,当我尝试退出之前的任何作业时,例如使用exit(3),它会抛出异常和整个堆栈。我找了一种方法来捕获这个异常并且不显示整个错误/堆栈,但没有运气。我尝试添加一个像下面这样的监听器,但它仍然打印整个堆栈。在正常终止之前退出阻塞调度员工作的正确方法是什么?

def make_db_snapshot(dataset, args):
    databases = ''

    print_header()

    snapshots_no = count_snapshots(dataset)
    ....

def scheduler_listener(event):
    log.debug('event code: {}'.format(event.__dict__))
    if event.code == 8192:
        log.error('The job crashed')
    log.debug('event code: {}'.format(event.code))


scheduler = BlockingScheduler()
scheduler.configure(executors=executors)
scheduler.add_listener(scheduler_listener, EVENT_JOB_EXECUTED | 
EVENT_JOB_ERROR)

# snapshot
scheduler.add_job(make_db_snapshot, trigger='cron',
                  name='DB snapshot', minute=SNAPSHOT['minute'],
                  hour=SNAPSHOT['hour'], args=[ZFS['dataset'], ARGS])

try:
    scheduler.start()
except (KeyboardInterrupt, SystemExit):
    exit(0)

这是我需要退出的地方:

def print_header():
    if not proc_is_running(DB['process_name']):
        log.error('DB process <{0}> is NOT running, exiting job'.
                  format(DB['process_name']))
        exit(5)

    log.info('{:=^70}'.format('='))
    ....

这就是我得到的:

INFO: Running job "DB snapshot (trigger: cron[hour='*', minute='*/1'], next 
run at: 2017-10-20 13:53:00 CEST)" (scheduled at 2017-10-20 13:52:00+02:00)
DEBUG: checking if process mysqld is running
ERROR: DB process <mysqld> is NOT running, exiting job
ERROR: Job "DB snapshot (trigger: cron[hour='*', minute='*/1'], next run at: 
2017-10-20 13:53:00 CEST)" raised an exception
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-
  packages/apscheduler/executors/base.py", line 125, in run_job
    retval = job.func(*job.args, **job.kwargs)
  File "./db-backup", line 198, in make_db_snapshot
    print_header()
  File "./db-backup", line 289, in print_header
    exit(5)
  File "/usr/lib/python3.5/_sitebuiltins.py", line 26, in __call__
    raise SystemExit(code)
SystemExit: 5
DEBUG: event code: {'traceback': '  File "/usr/local/lib/python3.5/dist-
packages/apscheduler/executors/base.py", line 125, in run_job\n    retval = 
job.func(*job.args, **job.kwargs)\n  File "./db-backup", line 198, in 
make_db_snapshot\n    print_header()\n  File "./db-backup", line 289, in 
print_header\n    exit(5)\n  File "/usr/lib/python3.5/_sitebuiltins.py", 
line 26, in __call__\n    raise SystemExit(code)\n', 'exception': 
SystemExit(5,), 'retval': None, 'job_id': 
'd0ba1527e68a460da44b4b4dde618552', 'code': 8192, 'scheduled_run_time': 
datetime.datetime(2017, 10, 20, 13, 52, tzinfo=<DstTzInfo 'Europe/Oslo' 
CEST+2:00:00 DST>), 'jobstore': 'default', 'alias': None}
ERROR: The job crashed
DEBUG: event code: 8192

1 个答案:

答案 0 :(得分:0)

永远不要在工作中使用sys.exit。提高异常。如果您不希望APScheduler处理异常,请在APScheduler之前自行处理。

我假设您正在使用ThreadPool执行程序(这是默认设置)。在一个帖子中,sys.exit会引发SystemExit错误。这就是APScheduler根据您的日志捕获的,这是100%正常。 APScheduler将始终尝试捕获并记录来自您的作业的任何异常(以避免丢失底层线程/进程)。即使sys.exit(0)在作业中也是异常的:APScheduler希望您通过让作业的函数返回而不会抛出任何异常来结束作业。

在您的情况下,您可能会发现在APScheduler可以之前自己捕获异常很方便:

class StopJob(BaseException):
    pass

def print_header():
    if not proc_is_running(DB['process_name']):
        raise StopJob('DB process <{0}> is NOT running.'.format(DB['process_name']))

    log.info('{:=^70}'.format('='))

def make_db_snapshot(dataset, args):
    try:
        do_stuff(dataset, args)
        print_headers()
        do_other_stuff()
    except StopJob:
        logger.exception('Stopping job.')
        # APScheduler won't notice the exception because it is handled, but it will be logged anyways.

但是,我认为让APScheduler为您处理异常并没有错。只需提出DBConnectionError而不是sys.exit,让APScheduler显示错误。毕竟这有什么问题?