J'essaie de construire une file d'attente de tâches en utilisant deux serveurs maîtres redis dans deux zones de disponibilité EC2. Toutes les opérations LPUSH sont effectuées dans la couche applicative vers les deux machines maîtres dans les deux zones de disponibilité. Idéalement, je devrais utiliser La resque de GitHub mais resque ne semble pas avoir de notion de plusieurs maîtres dans plusieurs Z.
Je dois m'assurer qu'un seul travailleur travaille sur une tâche donnée. Certains travailleurs seront dans l'AZ 1A en train de parler à la machine redis en 1A, et d'autres seront dans l'AZ 1B en train de parler à la machine en 1B. Je dois éviter le scénario où un travailleur en 1A et un travailleur en 1B déquettent le même travail à partir de différents maîtres redis et essaient de travailler dessus simultanément.
Ce pseudo-code de travailleur présente-t-il des conditions de course que j'ai pu manquer ?
job_id = master1.BRPOPLPUSH "queue", "working"
m1lock = master1.SETNX "lock.#{job_id}"
m2lock = master2.SETNX "lock.#{job_id}"
completed = master1.ZSCORE "completed", job_id
if completed
# must have been completed just now on other server, no-op
master1.LREM "working", 0, job_id
master1.del "lock.#{job_id}"
master2.del "lock.#{job_id}"
elsif not m1lock or not m2lock
# other server is working on it? We will put back at the end of our queue
master1.LPUSH "queue", job_id
master1.LREM "working", 0, job_id
master1.del "lock.#{job_id}" if m1lock
master2.del "lock.#{job_id}" if m2lock
else
# have a lock, it's not complete, so do work
do_work(job_id)
now = Time.now.to_i
master1.ZADD "completed", now, job_id
master2.ZADD "completed", now, job_id
master1.del "lock.#{job_id}"
master2.del "lock.#{job_id}"
master1.LREM "working", 0, job_id
master2.LREM "queue", 0, job_id # not strictly necessary b/c of "completed"
end