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