You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

APScheduler进程重启后错过的Cron任务未执行,求排查解决

问题:APScheduler错过的Cron任务重启后未执行

APScheduler版本:3.10.4

我做了如下测试:

  • 设置一个30秒后执行的Cron任务
  • 终止调度器进程,等待1-2分钟后重启
  • 预期行为:错过的任务在进程重启后立即执行

实际情况:

  • Redis服务器全程运行,已通过redis-cli确认任务状态已持久化
  • 使用SQLAlchemy存储方案也复现了相同问题
  • 重启后任务完全未执行,始终处于错过状态

上线前必须解决该错过任务的恢复问题,以下是可复现问题的clock.py脚本:

# apscheduler version 3.10.4

import logging
import os
import sys
import urllib.parse

from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.schedulers.blocking import BlockingScheduler
from pytz import utc

# Without this, the paths to `snake` modules etc. will not be located.
sys.path.append(os.path.join(os.path.dirname(__file__), "mysite"))

import django

django.setup()

from django.conf import settings

logging.basicConfig()
# The string "apscheduler" is necessary for logs to give good output.
logging.getLogger('apscheduler').setLevel(logging.DEBUG)


# WEB_CONCURRENCY is set by Heroku dynos automatically
number_of_cores = int(os.environ.get("WEB_CONCURRENCY", os.cpu_count() or 1))


parsed_redis_url = urllib.parse.urlparse(settings.REDIS_URL)
redis_job_store = RedisJobStore(
    host=parsed_redis_url.hostname,
    port=parsed_redis_url.port,
    password=parsed_redis_url.password,
    db=settings.CACHE_REDIS_DB,
    ssl=True if parsed_redis_url.scheme == "rediss" else False,
    ssl_cert_reqs=None,
)

# ==========
## APScheduler Configuration

job_defaults = {
    'max_instances': 1,
    'misfire_grace_time': 60 * 50,
    'coalesce': True
}

executors = {'default': ThreadPoolExecutor(number_of_cores)}


jobstores = {
    'default': redis_job_store,
}

scheduler = BlockingScheduler(
    executors=executors,
    logger=logging,
    job_defaults=job_defaults,
    timezone=utc,
    jobstores=jobstores,
)


@scheduler.scheduled_job('cron', hour=20, minute=38, second=40, name="print_ongoing", id="1")
def print_ongoing():
    from time import sleep

    from django.utils.crypto import get_random_string

    unique_id = get_random_string(length=4)
    s = 0
    while s < 1000:
        print(unique_id)
        s += 1
        sleep(1)


scheduler.start()

此外,Redis中序列化后的任务内容如下:

{
    'version': 1,
    'id': '1',
    'func': '__main__:print_ongoing',
    'trigger': {
        '__type__': 'apscheduler.triggers.cron.CronTrigger',
        'timezone': 'pytz._UTC',
        'start_date': None,
        'end_date': None,
        'fields': [
            {
                '__type__': 'apscheduler.triggers.cron.fields.BaseField',
                'name': 'year',
                'is_default': True,
                'expressions': [
                    {
                        '__type__': 'apscheduler.triggers.cron.expressions.AllExpression',
                        'step': None
                    }
                ]
            },
            {
                '__type__': 'apscheduler.triggers.cron.fields.MonthField',
                'month': None,
                'range': None,
                'expressions': [
                    {
                        'day': None,
                        'range': None
                    }
                ]
            },
            {
                '__type__': 'apscheduler.triggers.cron.fields.DayOfMonthField',
                'day': None,
                'range': None,
                'expressions': [
                    {
                        'day': None,
                        'range': None
                    }
                ]
            },
            {
                '__type__': 'apscheduler.triggers.cron.fields.WeekField',
                'week': None,
                'range': None,
                'expressions': [
                    {
                        'week': None,
                        'range': None
                    }
                ]
            },
            {
                '__type__': 'apscheduler.triggers.cron.fields.DayOfWeekField',
                'day_of_week': None,
                'range': None,
                'expressions': [
                    {
                        'day_of_week': None,
                        'range': None
                    }
                ]
            },
            {
                'hour': None,
                'range': {
                    'first': 20,
                    'last': 20
                }
            },
            {
                'minute': None,
                'range': {
                    'first': 20,
                    'last': 20
                }
            },
            {
                'second': None,
                'range': {
                    'first': 20,
                    'last': 20
                }
            }
        ]
    },
    'jitter': None,
    'executor': 'default',
    'args': None,
    'kwargs': {
        'print_ongoing': None
    },
    'misfire_grace_time': 3000,
    'coalesce': True,
    'max_instances': 1,
    'next_run_time': '2024-02-16 00:20:00'
}

内容的提问来源于stack exchange,提问作者Jack Kinsella

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:24:52