如何更早地 exit/terminate 作业并处理 apscheduler 中引发的异常?
How to exit/terminate a job earlier and handle the raised exception in apscheduler?
我有一个阻塞调度程序启动 3 个作业,没什么特别的。问题是,当我尝试退出之前的任何作业时,例如使用 exit(3)
,它会抛出异常和整个堆栈。我寻找一种方法来捕获此异常而不显示整个 error/stack,但没有运气。我尝试添加如下所示的侦听器,但它仍会打印整个堆栈。在正常终止之前退出 blockingscheduler 作业的正确方法是什么?
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
永远不要在工作中使用 sys.exit
。而是引发异常。如果不想让APScheduler处理异常,在APScheduler之前自己处理。
我假设您使用的是 ThreadPool 执行程序(这是默认设置)。在线程中,sys.exit
会引发 SystemExit
错误。这是 APScheduler 根据你的日志抓到的,这是 100% 正常的。 APScheduler 将始终尝试捕获并记录来自您的作业的任何异常(以避免丢失底层 thread/process)。即使 sys.exit(0)
在作业中也是异常的:APScheduler 希望您通过让作业的函数 return 结束作业而不抛出任何异常。
在您的情况下,您可能会发现在 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 显示错误。这到底有什么问题?
我有一个阻塞调度程序启动 3 个作业,没什么特别的。问题是,当我尝试退出之前的任何作业时,例如使用 exit(3)
,它会抛出异常和整个堆栈。我寻找一种方法来捕获此异常而不显示整个 error/stack,但没有运气。我尝试添加如下所示的侦听器,但它仍会打印整个堆栈。在正常终止之前退出 blockingscheduler 作业的正确方法是什么?
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
永远不要在工作中使用 sys.exit
。而是引发异常。如果不想让APScheduler处理异常,在APScheduler之前自己处理。
我假设您使用的是 ThreadPool 执行程序(这是默认设置)。在线程中,sys.exit
会引发 SystemExit
错误。这是 APScheduler 根据你的日志抓到的,这是 100% 正常的。 APScheduler 将始终尝试捕获并记录来自您的作业的任何异常(以避免丢失底层 thread/process)。即使 sys.exit(0)
在作业中也是异常的:APScheduler 希望您通过让作业的函数 return 结束作业而不抛出任何异常。
在您的情况下,您可能会发现在 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 显示错误。这到底有什么问题?