芹菜队列在其他网站上的行动

时间:2015-07-19 16:25:11

标签: django rabbitmq celery

嘿,我有一个问题,需要一些建议。我做了一些研究,但没有找到任何东西,这描述了我的确切问题。

我想要开发的过程:

  1. 许多用户可以触发操作,这会在我的队列中添加一些条目(RabbitMQ)
  2. 队列任务应该为网站获取登录名和密码(来自数据库[可能是多个帐户])并执行某些操作。这些操作返回某种结果,并与使用过的帐户一起保存在数据库中。
  3. 另一个计划任务(每5分钟一次)应该获取已保存的数据库条目并再次登录网站并执行其他一些操作。
  4. 问题:每个登录/密码组合只能同时登录。如果组合同时使用多次,则任务将相互注销。

    直到现在我才想到:

    1. 为每个登录/密码组合创建一个自己的队列,并为其设置一个工作人员,同时只处理一个条目。
    2. 锁定数据库中的行
    3. 您对此问题有任何建议或解决方案吗?

      我使用的框架是:Django作为主要的应用程序框架,Celery + RabbitMQ用于我的队列系统。

      EDIT1:
      http://docs.celeryproject.org/en/latest/tutorials/task-cookbook.html#ensuring-a-task-is-only-executed-one-at-a-time
      也许这篇文章可以帮助我..也许设置一个缓存键可能有所帮助。但是,如果所有登录/密码组合被"阻止"任务将遇到一些死锁问题。

1 个答案:

答案 0 :(得分:0)

使用某种锁定。

如果您可以容忍偶然的故障,那么您可以使用memcached或redis之类的东西进行快速而脏的分布式锁定。或者,正如您所说,您的数据库。

我不知道我是否甚至打扰数据库中的锁定行 - 我个人使用Redis并只创建映射

www.whatever.com:username:hash(password) -> worker hostname:worker pid:start time

然后您的工作人员可以检查网站/用户名/密码的特定组合是否被锁定。

使用flower还可以检查已锁定特定凭据集的工作人员是否仍处于活动状态。

将您的任务包装在try / except / finally块中,以确保在每个任务结束时释放锁定,即使它失败

import redis
r = redis.StrictRedis()

class MyTask(Task):
    __call__(site, username, password):
       key = '%s:%s:%s' % (site, username, hash(password) 
       val = '%s:%s:%s' % (datetime.now().isoformat(), self.request.hostname, os.getpid())

       if not setnx(key, val):
           LOG.error('%s locked', key)
           return

        try:
            return super(MyTask, self).__call__(site, username, password)
        finally:
            r.del(key)