Question

Je travaille sur un système qui doit gérer un certain nombre de conditions course au moment de servir des emplois à un certain nombre de travailleurs-machines.

Les clients pourraient interroger le système pour l'emploi avec status = « 0 » (Todo), puis, d'une manière atomique, mettre à jour la ligne la plus ancienne "avec état = « 1 »(verrouillé) et récupérer l'identifiant pour cette rangée (mise à jour du travail avec l'information des travailleurs comme machine qui travaille là-dessus, etc.).

La question principale ici est qu'il pourrait y avoir un certain nombre de clients la mise à jour en même temps. Une solution serait de verrouiller environ 20 des lignes avec le statut = « 0 », mettez à jour le plus ancien et libérer tous les verrous à nouveau par la suite. Je cherchais dans le TransactionMiddleware mais je ne vois pas comment cela empêcherait le cas de la plus ancienne étant mis à jour sous moi après que je l'interroger.

Je l'ai regardé dans le QuerySet.update () chose, et il semble prometteur, mais dans le cas de deux clients obtenir une prise du même dossier, la situation serait tout simplement mis à jour, et nous aurions deux travailleurs travaillant sur le même travail .. Je suis vraiment à une perte ici.

J'ai aussi trouvé un billet # 2705 qui semble bien gérer le cas, mais je aucune idée de comment obtenir le code à partir de là à cause de mon expérience limitée SVN (les dernières mises à jour sont tout simplement diffs, mais je ne sais pas comment fusionner avec le tronc que du code).

Code: Résultat = emploi

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)
Était-ce utile?

La solution

Pour fusionner # 2705 dans votre django, vous devez télécharger d'abord:

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

puis revenir en arrière svn à la version django nécessaire:

svn update -r11366

appliquer ensuite:

patch -p1 for_update_11366_cdestigter.diff

Il vous informera quels fichiers ont été patchés avec succès et qui n'étaient pas. Dans le cas peu probable des conflits, vous pouvez les fixer à la recherche manuellement http://code.djangoproject.com/attachment/ticket/2705/for_update_11366_cdestigter.diff

Pour unapply le patch, il suffit d'écrire

svn revert --recursive . 

Autres conseils

Si votre django est en cours d'exécution sur une machine, il est beaucoup plus simple façon de le faire ... Excusez le pseudo-code comme les détails de votre mise en œuvre ne sont pas claires.

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

Vous avez deux choix du haut de ma tête. La première consiste à verrouiller des lignes immédiatement après la récupération et seulement libérer le verrou une fois que celui approprié a été marquée comme en cours d'utilisation. Le problème ici est qu'aucun autre processus client peut même regarder les emplois qui ne vous laissez pas sélectionnés. Si vous êtes toujours juste de sélectionner automatiquement le dernier alors il peut être assez brève d'une fenêtre pour être Ö.K pour vous.

L'autre option serait de ramener les lignes qui sont ouvertes au moment de la requête, mais vérifiez à chaque fois que le client tente de saisir un emploi pour travailler avec. Lorsqu'un client tente de mettre à jour un emploi pour travailler sur un chèque serait d'abord fait pour voir si elle est toujours disponible. Si quelqu'un d'autre a déjà saisi il alors une notification sera envoyée au client. Cela permet à tous les clients de voir tous les emplois comme des instantanés, mais si elles sont constamment accaparement le dernier alors vous pourriez avoir les clients qui reçoivent constamment des notifications qu'un travail est déjà en cours d'utilisation. Peut-être cela est la condition de la course à laquelle vous faites référence?

Une façon de contourner ce serait de rendre les emplois dans des groupes spécifiques aux clients afin qu'ils ne reçoivent pas toujours les mêmes listes. Par exemple, les décomposer par zone géographique ou même simplement au hasard. Par exemple, chaque client pourrait avoir un ID de 0 à 9. Prenez le mod d'un ID sur les emplois et renvoyer ces emplois avec la même fin chiffres au client. Ne pas limiter à seulement ces emplois si, comme vous ne voulez pas qu'il y ait des emplois que vous ne pouvez pas atteindre. Ainsi, par exemple si vous avez des clients de 1, 2 et 3 et un travail de 104, alors personne ne serait en mesure d'y accéder. Ainsi, une fois il n'y a pas assez d'emplois avec les emplois corrects fin chiffres commenceraient à revenir avec d'autres chiffres juste pour remplir la liste. Vous devrez peut-être jouer avec l'algorithme exact, mais nous espérons que cela vous donne une idée.

Comment verrouiller les lignes dans votre base de données afin de les mettre à jour et / ou renvoyer les notifications en grande partie dépendra de votre SGBDR. Dans MS SQL Server, vous pouvez envelopper tout ce travail bien dans une procédure stockée aussi longtemps que l'intervention de l'utilisateur n'est pas nécessaire dans le milieu.

J'espère que cette aide.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top