Python 如何使用celerybeat测试自定义计划程序?

Python 如何使用celerybeat测试自定义计划程序?,python,couchbase,celerybeat,Python,Couchbase,Celerybeat,我正在用python为celerybeat编写一个自定义调度程序类,该类基于与mongodb一起工作的项目 事实上,我正试图用couchbase而不是mongodb来实现这一点。 我编写了一个ScheduleEntry类和一个Scheduler类,我从couchbase文档中获取Scheduler列表,并将其解析为ScheduleEntry对象,等等 但当我按照本文中的说明运行它时,似乎什么都没有发生 celery -A <my.task.file> beat -S <my.s

我正在用python为celerybeat编写一个自定义调度程序类,该类基于与mongodb一起工作的项目

事实上,我正试图用couchbase而不是mongodb来实现这一点。 我编写了一个ScheduleEntry类和一个Scheduler类,我从couchbase文档中获取Scheduler列表,并将其解析为ScheduleEntry对象,等等

但当我按照本文中的说明运行它时,似乎什么都没有发生

celery -A <my.task.file> beat -S <my.scheduler.CouchBaseScheduler>
然后我对Scheduler和SchedulerEntry类进行了子类化

class CouchBaseScheduler(Scheduler):

    UPDATE_INTERVAL = datetime.timedelta(seconds=5)

    Entry = CouchBaseScheduleEntry

    host = "192.168.59.103"
    port = "8091"
    bucket = "celery"
    doc_string = "scheduler_list"
    password = "1234"
    scheduleCount = 0

    def __init__(self, *args, **kwargs):
        if hasattr(current_app.conf, "CELERY_COUCHBASE_SCHEDULER_BUCKET"):
            bucket_str = current_app.conf.CELERY_COUCHBASE_SCHEDULER_BUCKET
        else:
            bucket_str = "celery"
        if hasattr(current_app.conf, "CELERY_COUCHBASE_SCHEDULER_URL"):
            cnx_string = "{}/{}".format(current_app.conf.CELERY_COUCHBASE_SCHEDULER_URL, bucket_str)
        else:
            cnx_string = "couchbase://{}:{}/{}".format(self.host, self.port, self.bucket)

        try:
            self.bucket = Bucket(cnx_string, password=self.password, quiet=True)
            self.couchcel = CouchBaseCelery(self.bucket, self.doc_string)
            get_logger(__name__).info("backend scheduler using %s", cnx_string)
            self._schedule = {}
            self._last_updated = None
            Scheduler.__init__(self, *args, **kwargs)
            self.max_interval = (kwargs.get('max_interval')
                             or self.app.conf.CELERYBEAT_MAX_LOOP_INTERVAL or 5)
        except AuthError:
            get_logger(__name__).error("Couchbase connection %s failed : Auth failed!", cnx_string)
        except CouchbaseError as cbe:
            get_logger(__name__).debug("Couchbase connection %s failed : %s", cnx_string, type(cbe))


    def setup_schedule(self):
        pass

    def requires_update(self):
        if not self._last_updated:
            return True
        return self._last_updated + self.UPDATE_INTERVAL < datetime.datetime.now()

    def get_from_database(self):
        self.sync()
        try:
            get_logger(__name__).info("Getting scheduler list from couchbase.")
            couch_scheduler_list = self.couchcel.get_scheduler_list()
            return couch_scheduler_list
        except Exception as e:
            get_logger(__name__).error("Could not get scheduler list from couchbase: {}".format(e))

    @property
    def schedule(self):
        # self.scheduleCount += 1
        # get_logger(__name__).info("Scheduling {}".format(self.scheduleCount))
        if self.requires_update():
            get_logger(__name__).info("Schedule {} requires update".format(self.scheduleCount))
            self._schedule = self.get_from_database()
            self._last_updated = datetime.datetime.now()
        return self.schedule

    def sync(self):
        for entry in self._schedule.values():
            entry.save(self.couchcel)
class CouchBaseScheduler(调度程序):
更新间隔=datetime.timedelta(秒=5)
Entry=CouchBaseScheduleEntry
host=“192.168.59.103”
端口=“8091”
bucket=“芹菜”
doc\u string=“调度程序列表”
密码=“1234”
scheduleCount=0
定义初始化(self,*args,**kwargs):
如果hasattr(当前_app.conf,“芹菜”\u COUCHBASE\u调度器\u BUCKET”):
bucket\u str=当前的\u app.conf.芹菜\u COUCHBASE\u调度程序\u bucket
其他:
bucket_str=“芹菜”
如果hasattr(当前的app.conf,“芹菜”\u COUCHBASE\u调度器\u URL”):
cnx_string=“{}/{}”。格式(当前_app.conf.芹菜_COUCHBASE_调度程序_URL,bucket_str)
其他:
cnx_string=“couchbase://{}:{}/{}”。格式(self.host、self.port、self.bucket)
尝试:
self.bucket=bucket(cnx_字符串,密码=self.password,quiet=True)
self.couchcel=couchbasecelly(self.bucket,self.doc\u字符串)
获取日志程序(\uuuuu name\uuuuu).info(“使用%s的后端计划程序”,cnx\u字符串)
self._schedule={}
self.\u last\u updated=无
调度程序._初始化(self,*args,**kwargs)
self.max\u interval=(kwargs.get('max\u interval'))
或self.app.conf.CELERYBEAT\u MAX\u LOOP\u INTERVAL或5)
除AuthError外:
获取日志(\uuuuu name\uuuu)。错误(“Couchbase连接%s失败:身份验证失败!”,cnx\u字符串)
除CouchbaseError作为cbe外:
获取记录器(uuu name_uuu)。调试(“Couchbase连接%s失败:%s”,cnx_字符串,类型(cbe))
def设置计划(自我):
通过
def需要_更新(自我):
如果不是自上次更新:
返回真值
返回self.\u last\u updated+self.UPDATE\u INTERVAL

类CouchBaseScheduleEntry(ScheduleEntry):
定义初始化(self、taskid、task):
self.\u task=任务
self.app=current\u app.\u get\u current\u object()
self.\u id=taskid
获取记录器(uuu name_uuu).info(“任务id:{}处理”.format(self.id))
尝试:
如果全部(k in self.\u k in的任务('name','task','enabled'):
self.name=self.\u任务['name']
self.task=self.\u task['task']
其他:
引发异常(“字段名、任务或已启用是必需的!”)
self.args=self.\u任务['args']
self.kwargs=self.\u任务['kwargs']
self.options=self.\u任务['options']
如果self.\u任务中的“interval”和self.\u任务中的“crontab”:
引发异常(“无法同时定义间隔和crontab计划”)
如果“间隔”在self.\u任务中:
间隔=自我。_任务['interval']
如果间隔['period']以周期为单位:
self.schedule=self.\u interval\u schedule(interval['period'],interval['every']))
获取记录器(\uuuuu名称\uuuuu).info(“任务包含间隔”)
其他:
引发异常(“间隔的值必须为{}”。格式(句点))
elif“crontab”在self.\u任务中:
crontab=self.\u任务['crontab']
self.schedule=self.\u crontab\u计划(crontab)
获取记录器(uuuuu name_uuuuu).info(“任务包含crontab”)
其他:
引发异常(“必须定义间隔或crontab计划”)
如果self.\u任务['total\u run\u count']为无:
self.\u任务['total\u run\u count']=0
self.total\u run\u count=self.\u任务['total\u run\u count']
获取记录器(uuu name_uuu).info(“任务总运行计数:{}.”格式(self.total_u运行计数))
如果不是self.\u任务['last_run_at']:
self.\u任务['last\u run\u at']=self.\u default\u now()
其他:
self.\u任务['last\u run\u at']=datetime.datetime.strtime(self.\u任务['last\u run\u at'],日期格式)
self.last\u run\u at=self.\u任务['last\u run\u at']
获取日志(uuu name_uuu).info(“任务上次运行时间:{}”.format(self.last_u运行时间))
除KeyError外,如下所示:
打印('键无效:{}'。格式(ke))
定义默认值(自我):
返回self.app.now()
def next(自我):
self.\u任务['last\u run\u at']=self.app.now()
self.\u任务['total\u run\u count']+=1
self.\u任务['run\u instally']=False
获取日志(\uuuuu name\uuuuu).info(“下一步!”)
返回self.\u类(self.\u任务)
__下一个
def到期(自):
如果不是自任务[“已启用”]:
返回False,延迟5.0#5秒
class CouchBaseScheduler(Scheduler):

    UPDATE_INTERVAL = datetime.timedelta(seconds=5)

    Entry = CouchBaseScheduleEntry

    host = "192.168.59.103"
    port = "8091"
    bucket = "celery"
    doc_string = "scheduler_list"
    password = "1234"
    scheduleCount = 0

    def __init__(self, *args, **kwargs):
        if hasattr(current_app.conf, "CELERY_COUCHBASE_SCHEDULER_BUCKET"):
            bucket_str = current_app.conf.CELERY_COUCHBASE_SCHEDULER_BUCKET
        else:
            bucket_str = "celery"
        if hasattr(current_app.conf, "CELERY_COUCHBASE_SCHEDULER_URL"):
            cnx_string = "{}/{}".format(current_app.conf.CELERY_COUCHBASE_SCHEDULER_URL, bucket_str)
        else:
            cnx_string = "couchbase://{}:{}/{}".format(self.host, self.port, self.bucket)

        try:
            self.bucket = Bucket(cnx_string, password=self.password, quiet=True)
            self.couchcel = CouchBaseCelery(self.bucket, self.doc_string)
            get_logger(__name__).info("backend scheduler using %s", cnx_string)
            self._schedule = {}
            self._last_updated = None
            Scheduler.__init__(self, *args, **kwargs)
            self.max_interval = (kwargs.get('max_interval')
                             or self.app.conf.CELERYBEAT_MAX_LOOP_INTERVAL or 5)
        except AuthError:
            get_logger(__name__).error("Couchbase connection %s failed : Auth failed!", cnx_string)
        except CouchbaseError as cbe:
            get_logger(__name__).debug("Couchbase connection %s failed : %s", cnx_string, type(cbe))


    def setup_schedule(self):
        pass

    def requires_update(self):
        if not self._last_updated:
            return True
        return self._last_updated + self.UPDATE_INTERVAL < datetime.datetime.now()

    def get_from_database(self):
        self.sync()
        try:
            get_logger(__name__).info("Getting scheduler list from couchbase.")
            couch_scheduler_list = self.couchcel.get_scheduler_list()
            return couch_scheduler_list
        except Exception as e:
            get_logger(__name__).error("Could not get scheduler list from couchbase: {}".format(e))

    @property
    def schedule(self):
        # self.scheduleCount += 1
        # get_logger(__name__).info("Scheduling {}".format(self.scheduleCount))
        if self.requires_update():
            get_logger(__name__).info("Schedule {} requires update".format(self.scheduleCount))
            self._schedule = self.get_from_database()
            self._last_updated = datetime.datetime.now()
        return self.schedule

    def sync(self):
        for entry in self._schedule.values():
            entry.save(self.couchcel)
class CouchBaseScheduleEntry(ScheduleEntry):

    def __init__(self, taskid, task):
        self._task = task

        self.app = current_app._get_current_object()
        self._id = taskid
        get_logger(__name__).info("Task id: {} processing".format(self._id))
        try:
            if all(k in self._task for k in ('name', 'task', 'enabled')):
                self.name = self._task['name']
                self.task = self._task['task']
            else:
                raise Exception("Field name, task or enabled are mandatory!")

            self.args = self._task['args']
            self.kwargs = self._task['kwargs']
            self.options = self._task['options']

            if 'interval' in self._task and 'crontab' in self._task:
                raise Exception("Cannot define both interval and crontab schedule")
            if 'interval' in self._task:
                interval = self._task['interval']
                if interval['period'] in PERIODS:
                    self.schedule = self._interval_schedule(interval['period'], interval['every'])
                    get_logger(__name__).info("Task contains interval")
                else:
                    raise Exception("The value of an interval must be {}".format(PERIODS))
            elif 'crontab' in self._task:
                crontab = self._task['crontab']
                self.schedule = self._crontab_schedule(crontab)
                get_logger(__name__).info("Task contains crontab")
            else:
                raise Exception("You must define interval or crontab schedule")

            if self._task['total_run_count'] is None:
                self._task['total_run_count'] = 0
            self.total_run_count = self._task['total_run_count']
            get_logger(__name__).info("Task total run count: {}".format(self.total_run_count))

            if not self._task['last_run_at']:
                self._task['last_run_at'] = self._default_now()
            else:
                self._task['last_run_at'] = datetime.datetime.strptime(self._task['last_run_at'], DATEFORMAT)
            self.last_run_at = self._task['last_run_at']
            get_logger(__name__).info("Task last run at: {}".format(self.last_run_at))
        except KeyError as ke:
            print('Key not valid: {}'.format(ke))

    def _default_now(self):
        return self.app.now()

    def next(self):
        self._task['last_run_at'] = self.app.now()
        self._task['total_run_count'] += 1
        self._task['run_immediately'] = False
        get_logger(__name__).info("NEXT!")
        return self.__class__(self._task)

    __next__ = next

    def is_due(self):
        if not self._task['enabled']:
            return False, 5.0 # 5 secs delay for reenable
        if self._task['run_immediately']:
            # figure out when the schedule would run next anyway
            _, n = self.schedule.is_due(self.last_run_at)
            return True, n
        return self.schedule.is_due(self.last_run_at)

    def _crontab_schedule(self, crontab):
        return celery.schedules.schedule(minute=crontab['minute'],
                                         hour=crontab['hour'],
                                         day_of_week=crontab['day_of_week'],
                                         day_of_month=crontab['day_of_month'],
                                         month_of_year=crontab['month_of_year'])

    def _interval_schedule(self, period, every):
        return celery.schedules.schedule(datetime.timedelta(**{period: every}))


    def __repr__(self):
        return '<CouchBaseScheduleEntry ({0} {1}(*{2}, **{3}) {{4}})>'.format(
            self.name, self.task, self.args,
            self.kwargs, self.schedule
        )

    def reserve(self, entry):
        new_entry = Scheduler.reserve(self, entry)
        return new_entry

    @property
    def getid(self):
        return self._id

    @property
    def gettaskdict(self):
        return self._task

    def tojson(self):
        return json.dumps(self.tocouchdict())

    def save(self, couchcel):
        get_logger(__name__).info("Saving task {} in couchbase".format(self._id))
        if self.total_run_count > self._task['total_run_count']:
            self._task['total_run_count'] = self.total_run_count
        get_logger(__name__).error("{}, {}".format(self.last_run_at, self._task['last_run_at']))
        try:
            if self.last_run_at and self._task['last_run_at'] \
                    and self.last_run_at > self._task['last_run_at']:
                self._task['last_run_at'] = self.last_run_at

        except TypeError:
            if self.last_run_at and self._task['last_run_at'] \
                    and self.last_run_at > datetime.datetime.strptime(self._task['last_run_at'], DATEFORMAT):
                self._task['last_run_at'] = self.last_run_at
        self._task['run_immediately']= False
        couchcel.save_scheduler(self)
celery -A <my.task.file> beat --scheduler <my.scheduler.CouchBaseScheduler>