1

我对 Python 和 Tornado 还很陌生,所以如果我把一个长期解决的问题复杂化了,请原谅,但我没有找到太多其他东西。

我正在为一个应用程序运行多个 Tornado 实例(每个服务器多个实例,多个服务器),并且有一些只有一个实例应该执行的任务,例如在应用程序中调度某些事件。我不想运行执行此任务的专用实例,而是希望采用一种机会主义方法,让第一个尝试完成这项工作的实例。

我的解决方案的一部分是基于数据库的锁定机制 (MongoDB findAndUpdate)。下面的代码似乎工作得很好,但如果这是一个好的解决方案,或者是否有现成的锁定和任务分配解决方案用于 Tornado,我想得到一些建议。

这是在进入函数时获取锁并在之后释放它的装饰器:

def locking(fn):
    @tornado.gen.engine
    def wrapped(wself, *args, **kwargs):
        @tornado.gen.engine
        def wrapped_callback(*cargs, **ckwargs):
            logging.info("release lock")
            yield tornado.gen.Task(lock.release_lock)
            logging.info("release lock done")
            original_callback(*cargs, **ckwargs)

        logging.info("acquire lock")
        yield tornado.gen.Task(model.SchedulerLock.initialize_lock, area_id=wself.area_id)
        lock = yield tornado.gen.Task(model.SchedulerLock.acquire_lock, area_id=wself.area_id)
        if lock:
            logging.info("acquire lock done")
            original_callback = kwargs['callback']
            kwargs['callback'] = wrapped_callback
            fn(wself, *args, **kwargs)
        else:
            logging.info("acquire lock not possible, postponed")
            ioloop = tornado.ioloop.IOLoop.instance()
            ioloop.add_timeout(datetime.timedelta(seconds=2), functools.partial(wrapped, wself, *args, **kwargs))

    return wrapped

acquire_lock方法返回锁对象或False

对此有什么想法吗?我知道锁只是解决方案的一半,因为我还需要一种机制来确保一次性任务只完成一次。然而,这可以非常相似地实现。有什么可以更优雅地解决问题的吗?

4

0 回答 0