我正在开发一个系统,该系统在为许多工作机器提供工作时必须处理许多竞争条件。
客户端将向系统查询 status='0' (ToDo) 的作业,然后以原子方式更新 status='1' (Locked) 的 'oldest' 行并检索该行的 id(用于更新带有工人信息的工作,例如正在使用哪台机器等)。
这里的主要问题是可能有任意数量的客户端同时更新。一种解决方案是锁定大约 20 个状态为“0”的行,更新最旧的行,然后再次释放所有锁。我一直在研究 TransactionMiddleware,但我不明白这将如何防止在我查询它后从我下面更新最旧的情况。
我已经研究了 QuerySet.update() 事情,它看起来很有希望,但是如果两个客户持有相同的记录,状态会简单地更新,我们会有两个工作人员从事同一个工作..我真的很茫然。
我还发现票#2705似乎可以很好地处理此案,但由于我有限的 SVN 经验,我不知道如何从那里获取代码(最后的更新只是差异,但我不知道如何合并与代码的主干)。
代码:结果 = 工作
class Result(models.Model):
"""
Result: completed- and pending runs
'ToDo': job hasn't been acquired by a client
'Locked': job has been acquired
'Paused'
"""
# relations
run = models.ForeignKey(Run)
input = models.ForeignKey(Input)
PROOF_CHOICES = (
(1, 'Maybe'),
(2, 'No'),
(3, 'Yes'),
(4, 'Killed'),
(5, 'Error'),
(6, 'NA'),
)
proof_status = models.IntegerField(
choices=PROOF_CHOICES,
default=6,
editable=False)
STATUS_CHOICES = (
(0, 'ToDo'),
(1, 'Locked'),
(2, 'Done'),
)
result_status = models.IntegerField(choices=STATUS_CHOICES, editable=False, default=0)
# != 'None' => status = 'Done'
proof_data = models.FileField(upload_to='results/',
null=True, blank=True)
# part of the proof_data
stderr = models.TextField(editable=False,
null=True, blank=True)
realtime = models.TimeField(editable=False,
null=True, blank=True)
usertime = models.TimeField(editable=False,
null=True, blank=True)
systemtime = models.TimeField(editable=False,
null=True, blank=True)
# updated when client sets status to locked
start_time = models.DateTimeField(editable=False)
worker = models.ForeignKey('Worker', related_name='solved',
null=True, blank=True)