Frage

Ich bin auf einem System arbeiten, das eine Reihe von Rennbedingungen zu behandeln hat, wenn Aufträge an eine Anzahl von Arbeitsmaschinen dienen.

Die Kunden würden das System für Aufträge mit Status abfragen = ‚0‘ (ToDo), dann, in einer atomaren Weise, aktualisieren Sie die ‚älteste‘ Zeile mit Status = ‚1‘ (gesperrt) und rufen Sie die ID für diese Zeile (für die Aktualisierung des Jobs mit Arbeitern Informationen wie, welche Maschine auf mich usw. funktioniert.).

Das Hauptproblem ist hier, dass es möglicherweise ein beliebige Anzahl von Kunden sein zur gleichen Zeit zu aktualisieren. Eine Lösung wäre, um 20 der Zeilen zu sperren mit Status = ‚0‘, die ältesten aktualisieren und lassen Sie alle die Sperren wieder danach. Ich habe in die TransactionMiddleware suchen, aber ich sehe nicht, wie dies den Fall des ältesten wurde aktualisiert unter mir verhindern würde, nachdem ich es abgefragt werden.

Ich habe in den QuerySet.update () Ding sah, und es sieht vielversprechend aus, aber im Fall von zwei Kunden ein Halten des gleichen Datensatzes erhalten, würde der Status einfach aktualisiert, und wir würden zwei Arbeiter haben arbeiten die gleiche Arbeit .. ich bin hier bei einem Verlust wirklich.

ich auch Tickets # 2705 , die den Fall gut zu handhaben scheint, aber ich habe keine Ahnung, wie von dort den Code zu bekommen wegen meiner begrenzten SVN Erfahrung (die letzten Updates sind einfach Diffs, aber ich weiß nicht, wie mit dem Stamm des Codes fusionieren, dass).

Code: Ergebnis = Job

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)
War es hilfreich?

Lösung

Um # 2705 in die django fusionieren, müssen Sie es herunterladen zuerst:

cd <django-dir>
wget http://code.djangoproject.com/attachment/ticket/2705/for_update_11366_cdestigter.diff?format=raw

dann zurückspulen SVN auf die notwendige django Version:

svn update -r11366

dann gilt es:

patch -p1 for_update_11366_cdestigter.diff

Es wird Ihnen mitteilen, welche Dateien erfolgreich gepatcht wurden und welche nicht. Im unwahrscheinlichen Fall von Konflikten können Sie sie manuell beheben bei http://code.djangoproject.com/attachment/ticket/2705/for_update_11366_cdestigter.diff suchen

Um Unapply der Patch nur Schreib

svn revert --recursive . 

Andere Tipps

Wenn Ihr django auf einer Maschine ausgeführt wird, gibt es eine viel einfachere Art und Weise, es zu tun ... Entschuldigen Sie den Pseudo-Code wie die Details der Implementierung nicht klar sind.

from threading import Lock

workers_lock = Lock()

def get_work(request):
    workers_lock.acquire()
    try:
        # Imagine this method exists for brevity
        work_item = WorkItem.get_oldest()
        work_item.result_status = 1
        work_item.save()
    finally:
        workers_lock.release()

    return work_item

Sie haben zwei Möglichkeiten aus der Spitze von meinem Kopf. Eine davon ist Zeilen sofort nach Abruf zu sperren und nur die Sperre wieder freigeben, sobald die geeigneten als in Gebrauch gekennzeichnet. Das Problem hierbei ist, dass kein anderer Client-Prozess auch bei den Jobs suchen kann, die nicht bekommen, ausgewählt. Wenn Sie immer nur automatisch die letzte Auswahl dann kann es eine kurze genug von einem Fenster sein o.k. für Sie.

Die andere Möglichkeit wäre es, die Reihen zu bringen, die zum Zeitpunkt der Abfrage offen sind, aber dann wieder zu überprüfen, wann immer der Client versucht, mit einem Job arbeiten zu greifen. Wenn ein Client versucht, einen Job zu Arbeit aktualisieren auf, es wäre zuerst eine Prüfung durchgeführt werden, um zu sehen, ob es noch verfügbar ist. Wenn jemand anderes es schon gepackt hat, dann wäre eine Mitteilung an den Kunden zurückgeschickt werden. Auf diese Weise können alle Clients alle Jobs als Schnappschüsse, um zu sehen, aber wenn sie ständig die neuesten einem erregenden sind dann könnten Sie die Kunden ständig Meldungen haben empfangen, dass ein Auftrag bereits in Gebrauch ist. Vielleicht ist das die Race-Bedingung, auf die Sie sich beziehen?

Ein Weg, um, dass die Arbeitsplätze in bestimmten Gruppen zu den Kunden zurückkehren würde, so dass sie nicht immer sind die gleichen Listen zu bekommen. Zum Beispiel bricht sie nach Regionen oder sogar zufällig gerade. Zum Beispiel könnte jeder Kunde eine ID von 0 bis 9 hat Nehmen Sie die mod einer ID auf den Arbeitsplätzen und sendet den Kunden diese Aufträge mit der gleichen Endung Ziffer zurück. Schränken sie nicht nur auf diese Arbeitsplätze obwohl, wie Sie nicht dort wollen Arbeitsplätze sein, dass Sie nicht erreichen kann. So zum Beispiel, wenn Sie Kunden von 1 haben, 2 und 3 und ein Auftrag von 104 dann niemand wäre in der Lage, um es zu bekommen. Also, wenn es nicht genug Arbeitsplätze mit den richtigen Endung stelligen Arbeitsplätzen beginnen würde, mit anderen Stellen wieder kommt nur die Liste zu füllen. Sie könnten hier mit dem genauen Algorithmus spielen müssen um, aber hoffentlich das gibt Ihnen eine Idee.

Wie Sie die Zeilen in Ihrer Datenbank sperren, um sie zu aktualisieren und / oder die Benachrichtigungen werden weitgehend auf Ihrem RDBMS abhängig zurückschicken. In MS SQL Server Sie all diese Arbeit schön in einer gespeicherten Prozedur solange Benutzereingriff ist nicht in der Mitte der es erforderlich wickeln könnten.

Ich hoffe, das hilft.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top