Hallo und einen guten Abend,
sry, an ein bsp. hatte ich heute mittag nicht mehr gedacht.
Ist aber nichts großartiges.
Code: Alles auswählen
@home_blueprint.route('/test', methods=['GET'])
def test():
thread_name = 'force_update'
if not TP.ForceUpdate().status_check()[0]: # PRÜFE OB PROZESS GERADE LÄUFT
TP.ForceUpdate().status_set('start_force_update'): # <-- FALLS NICHT, SETZE ICH GLEICH ALS ERSTES DEN WERT VON FALSE AUF TRUE
# start des Update in einem Thread. GANZ ZUM SCHLUSS SETZE ICH MIT ('stop_force_update')" den Wert wieder auf FALSE + setze datetime.now() einen Timestamp.
threading.Thread(target=TP.ForceUpdate().start_force_update, name=thread_name, daemon=False).start()
return 'Update Prozess startet. Bitte warten', 200
else:
if not TP.ForceUpdate().status_check()[1]:
return 'Update Prozess läuft gerade. Bitte warten.', 200
else:
return TP.ForceUpdate().status_check()[1], 200
....
def status_check(self):
force_update_status = self.session.query(db.Settings).filter(db.Settings.option == 'force_update_running').one()
if force_update_status.boolean:
return True, None
Kurze Erklärung:
Egal von wem nun diese Funktion aufgerufen wird, gleich zu Anfang wird mit "status_check" geprüft, läuft der Prozess oder nicht. Default Wert in der DB "false" und wir bei jedem start der Applikation wieder auf "false" gesetzt.
Wenn "true" == "Update Prozess läuft gerade..." ausgeben und schluss.
Wenn "false" == so setze ich gleich im nächsten Schritt den Wert mit ".status_set('start_force_update')" auf True. Jetzt startet der Update ... zum Schluss wird mit .status_set('stop_force_update') der Eintrag in der DB wieder auf "false" gesetzt.
Also statt jetzt den Thread mit ".is_alive()" oder ".enumerate()" und was es nicht alles noch gibt zu überprüfen ob dieser Thread/Prozess gerade läuft, setze ich ein einfaches True/False in die DB und kann dies jetzt unabhängig von Threads/Prozessen etc. abrufen. Ich denke, viel falsch kann man bei diesem Weg nicht machen.
Es ist nichts anderes als eine Variable "force_update_running" = True/False
Nur das eine einfache Variable, duch Threads/Prozesse, nicht problemlos/sicher von überall richtig ausgelesen werden kann. So ist nun die DB der Ersatz dieser Variable. Nichts anderes.
__deets__ hat geschrieben: ↑Montag 11. September 2023, 14:16
Ohne zu sehen, wie das mit der Datenbank geloest ist, kann man da nicht wirklich was zu sagen, ob es denn richtig funktioniert. Die hilft einem sicher dabei, weil sie einen Weg darstellt, einen verteilten Synchronisationsmechanismus aufzubauen. Ublicherweise durch select for update und Konsorten. Aber muss eben auch richtig gemacht werden.
Genau so in etwas habe ich es gelöst. Gleich zu Anfang das automatische zurücksetzen nach einem neustart, gleich als erstes eingebaut, war zu Anfang Gold wert

Am "Update Prozess" selbst, bin ich gerade noch dran. Hier muss ich nur aufpassen, sollte es mal zu einem Fehler kommen, weil die andere DB nicht abrufbar ist, etc. das dies nicht in einer exception landet und der Wert auf "True" verbleibt. Dies ist der einzige Punkt auf den ich achten muss, sonst kann es kein Celery, etc. besser. (ich rede jetzt nur von dieser einzigen Funktion)
Sirius3 hat geschrieben: ↑Montag 11. September 2023, 14:51
@chris_adnap: Datenbank alleine löst Dein Problem nicht, da braucht es auch eine explizite Synchronisation der Prozesse, automatisch passiert da gar nichts. Für viele Datenbanksysteme gibt es da entsprechende Mechanismen, die man aber kennen muß.
Welche Datenbank benutzt Du und wie sieht Deine Lösung jetzt aus?
Postgres ist die DB und mein Lösungsweg habe ich oben beschrieben.
Die Datenbank dient einzig und alleine dafür, zu hinterlegen, wurde die Funktion aufgerufen und läuft diese gerade. Mehr macht dies auch nicht.
Wie geschrieben, es ging mir einzig und allein darum, das diese Funktion jeweils immer nur 1x am laufen ist.
Ich weiß jetzt nicht wie hoch die Wahrscheinlichkeit dabei liegt, deswegen habe ich die Überprüfung und das Setzen des Wertes gleich hintereinander gelegt ...
Aber das rettet einen leider nicht davor, dass hier eine „race condition“ vorliegt. Wenn die Funktion zweimal aufgerufen wird, kann es passieren das beide im ``if`` zum Schluss kommen, dass gerade kein Update-Thread läuft bevor sie ihn dann beide starten.
... evtl. kann es hier auch zu einer „race condition“ kommen, wenn man 1000 Requests zur selbigen Zeit erhällt. Zwar ist die Wahrscheinlichkeit wesentlich geringer, als mit der der threading.enumerate() Schleife, aber nichts ist unmöglich.
Könnte man "verbessern" indem man nach dem Setzen nochmals weitere Checks unternimmt (Anzahl offener/laufendes Threads mit diesem Namen, etc.), aber dies wird in meinem Fall sicher nicht nötig sein, so viele Anfragen bzw. starten dieser einen Funktion erwarte ich nicht.
Und sollte es aus einem unwahrscheinlichen Grund doch einmal dazu kommen, dann läuft das eine mal diese Funktion 2x gleichzeitig... Egal.
Ich wollte einzig und alleine Resourcen auf meiner Seite und vorallem der Seite wo die Daten abgerufen werden, einsparen. Und dies sollte ich nun erreicht haben.
Ich bin mir jetzt aber sicher, das ich mit diesem Weg, nichts falsch gemacht habe und bin auf Feedback gespannt.
Viele Grüße
Chris