0

問題文:

ジョブストアにジョブを格納するように構成されているメソッド( Test::start())を追加しようとしています。ジョブストアへのジョブの追加は成功しました。しかし、スケジューラーを起動しようとすると、(in )は指定されたオブジェクトのを取得できません[この場合、指定されたオブジェクトは-つまり]です。scheduler.add_date_job()SQLAlchemyJobStoreobj_to_refapscheduler/util.pyref_to_obj()Test::start()<bound method Test.start of <__main__.Test instance at 0xa119a6c>>

ただし、次の場合、同じ操作が正常に機能します。

  1. その他のジョブストア(fe-RAMJobStoreこれは、ジョブストアが追加/構成されていない場合のデフォルトです)。
  2. scheduler.add_date_job()他の関数(func以下のコードではfe)で呼び出され、 Test::start()(ジョブストアがSQLAlchemyJobStore)[the andforis ]のようなメソッドref_to_obj()ではない場合。同じことを確認するために、いくつかのデバッグを(に)追加しました。obj_to_ref()func<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>

を(fe )ではなく(fe )に変更scheduler.add_date_job()するfunctionfuncmethodTest::start()

self.scheduler.add_date_job(func, alarm_time)

以下は、次のデバッグ出力ですfunc()

obj_to_ref : obj : <function func at 0xb768ed14>
obj_to_ref : ref : __main__:func
obj_to_ref : obj2 : <function func at 0xb768ed14>

私はここで何か間違ったことをしていますか?apscheduler/util.pyまたは、これは関数のバグSQLAlchemyJobStoreですか?

既知の回避策はありますか?!

4

1 に答える 1

1

主な問題は、SQLAlchemyJobStoreまたはそれ以外の他のジョブストアを使用している場合RAMJobStore、apschedulerはpickleを使用してジョブをシリアル化し、ストレージに保存することです。メソッドで指定した関数への参照名のみを保存しますscheduler.add_date_job

したがって、あなたの場合、それはのようなものを保存します<object id in memory>.start

したがって、ジョブ関数の場合は、インスタンスメソッドではなく、モジュールのトップレベルで定義された関数を使用する必要があります。

また、apschedulerが実行間でジョブ機能の状態を保存しないことも意味します。メソッド内のデータベースに状態の保存と読み込みを実装する必要がある場合があります。しかし、これは物事を複雑にしすぎるでしょう。

より良い方法は、ジョブを実行するタイミングを決定するカスタムスケジュールトリガークラスを実装することです。トリガーの状態をロード/保存する必要がある場合があります。そのため、スケジューラプロセスの停止と開始がサポートされます。

いくつかのリンク:

于 2013-02-12T04:26:52.730 に答える