J'ai une application web2py qui sert essentiellement d'interface de navigation pour un script Python. Ce script revient généralement assez rapidement, mais peut parfois prendre beaucoup de temps. Je veux fournir un moyen pour l'utilisateur d'arrêter l'exécution du script si cela prend trop de temps.Arrêt d'une action de longue durée dans web2py avec multiprocessing
J'appelle actuellement la fonction comme ceci:
def myView(): # this function is called from ajax
session.model = myFunc() # myFunc is from a module which i have complete control over
return dict(model=session.model)
myFunc
, lorsqu'elle est appelée avec certaines options, utilise multitraitement mais finit par prendre beaucoup de temps. J'ai besoin d'un moyen de terminer la fonction, ou à tout le moins les enfants du fil.
La première chose que j'ai essayé était de courir myFunc
dans un nouveau processus, et rouler mon propre système d'événement simple pour le tuer:
# in the controller
def myView():
p_conn, c_conn = multiprocessing.Pipe()
events = multiprocessing.Manager().dict()
proc = multiprocessing.Process(target=_fit, args=(options, events c_conn))
proc.start()
sleep(0.01)
session.events = events
proc.join()
session.model = p_conn.recv()
return dict(model=session.model)
def _fit(options, events pipe):
pipe.send(fitting.logistic_fit(options=options, events=events))
pipe.close()
def stop():
try:
session.events['kill']()
except SystemExit:
pass # because it raises that error intentionally
return dict()
# in the module
def kill():
print multiprocessing.active_children()
for p in multiprocessing.active_children():
p.terminate()
raise SystemExit
def myFunc(options, events):
events['kill'] = kill
je suis tombé sur quelques problèmes majeurs avec cela.
- La session
stop()
n'a pas toujours la même que la sessionmyView()
, doncsession.events
était pas. - Même lorsque la session était la même,
kill()
ne supprimait pas correctement les enfants. - La fonction à exécution longue bloquerait le thread web2py, donc
stop()
n'a même pas été traitée jusqu'à la fin de la fonction.
Je considérais pas join()
et appellent en utilisant AJAX pour récupérer le résultat de la fonction à un moment plus tard, mais je n'ai pas pu enregistrer l'objet de processus session
pour une utilisation ultérieure. Le tuyau semblait pouvoir être décapé, mais j'ai ensuite eu le problème de ne pas pouvoir accéder à la même session à partir d'une autre vue.
Comment puis-je implémenter cette fonctionnalité?
Pouvez-vous développer votre réponse? Quelques choses spécifiques qui mériteraient d'être répondues: Le planificateur démarre-t-il la tâche immédiatement, à partir d'un script? Comment obtenir le résultat de la tâche? Comment forcer-arrêter la tâche? Tel qu'il est, cela ne répond pas complètement à la question. – Scimonster
J'ai mis à jour la réponse pour répondre à votre dernière question. Vos deux premières questions sont abordées dans la documentation liée. Comme ils impliquent la fonctionnalité générale du planificateur et ne font pas partie de votre question initiale, je ne mettrai pas à jour la réponse, mais je mentionnerai brièvement que les nouvelles tâches sont immédiatement mises en file d'attente immédiatement (vous pouvez forcer un ouvrier à vérifier immédiatement la file d'attente 'immediate = True'), et la méthode' scheduler.task_status() 'est utilisée pour récupérer les résultats. – Anthony