2013-04-10 2 views
0

У меня есть одна очередь заданий с несколькими рабочими, наблюдающими за этой очередью. (каждое задание соответствует одному пользователю). В очереди может быть несколько заданий на пользователя в очереди.Проектирование системы очередей заданий, где работники могут обрабатывать только одно задание на каждого пользователя

Я не хочу, чтобы мои работники обрабатывали более 1 задания на пользователя в любой момент времени. Задача пользователя должна быть выбрана работником только в том случае, если в это время другой рабочий не обрабатывает этого пользователя. В случае, если работа пользователя обрабатывается рабочим, я также хочу, чтобы следующее задание пользователя было выбрано немедленно, как только оно будет завершено.

Я хочу, чтобы мои рабочие пользователи были агностиками (т.е. любой рабочий должен иметь возможность обрабатывать любую работу пользователя). Это поможет мне масштабироваться горизонтально.

Как мне это сделать? Я хотел бы создать отдельные очереди для каждого пользователя, но тогда работникам придется наблюдать огромное количество очередей и тратить ресурсы. Я использую beanstalkd в качестве сервера очереди прямо сейчас.

Любая помощь приветствуется.

ответ

0

Прежде всего позвольте мне сказать, что ограничение обработки одной работы на одного пользователя может привести к крайним задержкам обработки заданий для других пользователей. Рассмотрим сценарий, когда ваша очередь содержит большое последовательное количество заданий для пользователя1, за которым следует большое последовательное количество заданий для пользователя2 и т. Д. В результате вашей предлагаемой архитектуры вам придется слить свою очередь пользовательских заданий сначала, и только после этого начнутся процессы пользователя2, в результате чего пользователь3 будет долго ждать ...

Возможно, вы сможете чтобы облегчить ситуацию, введя несколько очередей (по-прежнему не для каждого пользователя) и в очередном порядке создавайте свою работу, но, как видите, это все еще не на 100% надежнее.

Однако, если вы действительно хотите гарантировать это требование одной (или несколькими) очередями, я бы посоветовал использовать какой-то общий механизм блокировки (например, memcached), чтобы поддерживать блокировки для каждого пользователя, пока работа для этого пользователя в процессе. This article описывает, как, и для этого есть gems. Затем вы можете использовать следующий алгоритм:

job = @beanstalkd.reserve 
user_id = job.body["user_id"] 
if (get_lock_for(user_id) 
    # process job 
    # .... 
    job.delete 
end