无法添加add_date_job()方法以在SQLAlchemyJobStore作业存储中存储作业

时间:2013-02-11 23:01:09

标签: python sqlalchemy scheduler apscheduler

问题陈述:

我正在尝试向Test::start()添加一个方法(scheduler.add_date_job()),该方法配置为将作业存储在SQLAlchemyJobStore作业存储中。将作业添加到作业库是成功的。但是当我尝试启动调度程序时,obj_to_ref(在apscheduler/util.py中)无法获取给定对象的ref_to_obj() [在这种情况下,给定的对象是{{1} - 换句话说,Test::start()]。

但在以下情况下,同样的操作正常:

  1. 其他工作存储(f.e。<bound method Test.start of <__main__.Test instance at 0xa119a6c>> - 这是未添加/配置工作存储的默认设置。
  2. 使用其他功能调用RAMJobStore时(以下代码中为fe scheduler.add_date_job())而不是func等方法(作业存储为Test::start())[{{ 1 {}和SQLAlchemyJobStore ref_to_obj()obj_to_ref()]。我添加了一些调试(在func中)以确认相同。
  3. 代码如下:

    <function func at 0xb768ed14>

    堆栈跟踪如下:

    apscheduler/util.py

    我在from apscheduler.scheduler import Scheduler as scheduler from datetime import datetime, date, time, timedelta import time import logging logging.basicConfig(filename='/tmp/log', level=logging.DEBUG, format='[%(asctime)s]: %(levelname)s : %(message)s') class Failed(Exception): def __str__(self): return 'Failed!!' # APScheduler Configure Options _g_aps_default_config = { 'apscheduler.standalone' : True, 'apscheduler.jobstore.default.class' : 'apscheduler.jobstores.sqlalchemy_store:SQLAlchemyJobStore', 'apscheduler.jobstore.default.url' : 'mysql://root:root123@localhost/jobstore', 'apscheduler.jobstore.default.tablename' : 'mytable' } class Test: def __init__(self, *args, **kwargs): self.scheduler = scheduler(_g_aps_default_config) self.__running = False # Intentionally don't want to start!! self.__dont_start = True self.__retry_count = 0 self.__start_max_retries = 5 def start(self): try: # Try to start here! # Intentionally don't want to start for the first 5 times if self.__retry_count < self.__start_max_retries: self.__retry_count += 1 raise Failed if self.__running: raise Failed self.__running = True print 'started successfully :)' except Failed: # log the start failure and reschedule the start() print 'attempt (#%d): unable to start now.. ' \ 'so rescheduling to start after 5 seconds' % self.__retry_count alarm_time = datetime.now() + timedelta(seconds=5) self.scheduler.add_date_job(self.start, alarm_time) self.scheduler.start() def func(): print 'this is a func and not a method!!!' if __name__ == '__main__': t = Test() t.start() while True: time.sleep(10) t.stop() 中添加的调试如下:

    Traceback (most recent call last):
      File "user1.py", line 55, in <module>
        t.start()
      File "user1.py", line 48, in start
        self.scheduler.start()
      File "/usr/lib/python2.7/site-packages/APScheduler-2.1.0-py2.7.egg/apscheduler/scheduler.py", line 109, in start
        self._real_add_job(job, jobstore, False)
      File "/usr/lib/python2.7/site-packages/APScheduler-2.1.0-py2.7.egg/apscheduler/scheduler.py", line 259, in _real_add_job
        store.add_job(job)
      File "/usr/lib/python2.7/site-packages/APScheduler-2.1.0-py2.7.egg/apscheduler/jobstores/sqlalchemy_store.py", line 58, in add_job
        job_dict = job.__getstate__()
      File "/usr/lib/python2.7/site-packages/APScheduler-2.1.0-py2.7.egg/apscheduler/job.py", line 120, in __getstate__
        state['func_ref'] = obj_to_ref(self.func)
      File "/usr/lib/python2.7/site-packages/APScheduler-2.1.0-py2.7.egg/apscheduler/util.py", line 174, in obj_to_ref
        raise ValueError('Cannot determine the reference to %s' % repr(obj))
    ValueError: Cannot determine the reference to <bound method Test.start of <__main__.Test instance at 0xa119a6c>>
    

    以下是apscheduler/util.py的调试打印:

    161 def obj_to_ref(obj):
    162     """
    163     Returns the path to the given object.
    164     """
    165     ref = '%s:%s' % (obj.__module__, get_callable_name(obj))
    166     print 'obj_to_ref : obj : %s' % obj
    167     print 'obj_to_ref : ref : %s' % ref
    168     try:
    169         obj2 = ref_to_obj(ref)
    170         print 'obj_to_ref : obj2 : %s' % obj2
    171         if obj != obj2:
    172             raise ValueError
    173     except Exception:
    174         raise ValueError('Cannot determine the reference to %s' % repr(obj))
    175 
    176     return ref
    

    Test::start()更改为obj_to_ref : obj : <bound method Test.start of <__main__.Test instance at 0xa119a6c>> obj_to_ref : ref : __main__:Test.start obj_to_ref : obj2 : <unbound method Test.start> (f.e。scheduler.add_date_job())而不是function(f.e。func

    method

    以下是Test::start()的调试打印:

    self.scheduler.add_date_job(func, alarm_time)
    

    我在这里做错了吗?或者这是func()函数w.r.t中的错误。 obj_to_ref : obj : <function func at 0xb768ed14> obj_to_ref : ref : __main__:func obj_to_ref : obj2 : <function func at 0xb768ed14>

    任何已知的解决方法?!

1 个答案:

答案 0 :(得分:1)

主要问题是当您使用SQLAlchemyJobStoreRAMJobStore之外的任何其他作业存储时,apscheduler会使用pickle将您的作业序列化以将其保存到存储中。 它仅将参考名称保存到您在scheduler.add_date_job方法中指定的函数。

因此,在您的情况下,它会保存<object id in memory>.start

之类的内容

因此,对于工作职能,您应该使用functions defined at the top level of a module而不是实例方法。

这也意味着apscheduler不会在运行之间保存作业功能状态。您可能需要在方法内部的数据库中实现保存和加载状态。但这会使事情变得太复杂。

更好的方法是实现自定义计划触发器类,该类将决定何时运行作业。您可能仍需要加载/保存触发器的状态 - 因此它将支持停止和启动调度程序进程。

一些链接: