1
votes

Comment limiter le temps d'exécution des requêtes?

Je suis censé répondre en 3 secondes.

Mon gestionnaire parle avec un serveur tiers, qui pourrait répondre en 3 secondes ou pas.

Je pense au code suivant - p>

class MainReply(webapp2.RequestHandler):
    def get(self):
        # do something
        # start task to talk with 3rd server
        for i in range(300): # wait 3 seconds
            # check task status
            # if finished, then break
            time.sleep(0.01)
        # if not finished, inform user

Est-ce une approche correcte? Ou y a-t-il une meilleure solution?

Mettre à jour. Je travaille sur le bot Voice Assistant (quelque chose de similaire à Google Assistant), où le bot doit répondre dans les 3 secondes. Et le bot ne peut pas lancer la réponse lui-même, c'est-à-dire que je ne peux pas donner une autre réponse, une fois la demande terminée. Et comme il s'agit d'un assistant vocal, je ne peux pas donner de lien. Je pensais à l'approche suivante - si je peux donner une réponse normale en 3 secondes, donnez-la. Sinon, demandez à l'utilisateur de demander à nouveau avec un mot simple comme "Statut".


3 Réponses :


0
votes

La règle de base est que vous ne devriez jamais faire un pool comme décrit dans votre article car (1) vous bloquez "manuellement" plus de ressources que nécessaire (2) vous gâchez votre code en simulant un code asynchrone qui ne l'est vraiment pas, et (3) Les langages fournissent généralement des outils pour gérer la programmation simultanée, qui sont spécialement conçus pour ce type de tâches, et cela fait le travail pour vous bien mieux que vous ne pourriez l'implémenter (dans la plupart des cas).

En suivant vos besoins. J'ai écrit un programme simple que vous pouvez tester. Consultez ici asyncio.wait_for code > documentation. Trouvez ici également un guide utile vers async.

Copiez le code dans un fichier et exécutez $ python [filename]

import asyncio
import random
from concurrent.futures._base import TimeoutError

async def safe_get():
    result = "I'm currently out of my office."
    try:
        result = await asyncio.wait_for(get(), 3)
    except TimeoutError as e:
        print("Responder thought too much about his answer")
    return result

async def get(a=1,b=6):
    random_time = random.randint(a,b)
    await asyncio.sleep(random_time)
    return "I'm doing good thanks! Sorry it took me " + str(random_time) + "s to answer."

async def main():
    # Toggle comment on the two following lines to see (1) unwanted behaviour and (2) wanted behaviour
    # response = await get()
    response = await safe_get()
    print(response)

if __name__ == "__main__":
    asyncio.run(main())


4 commentaires

Merci. Mais j'ai peur que cela ne fonctionne pas avec Google App Engine ... Mais voici l'option - cloud.google.com/appengine/docs/standard/python/…


Donc ça ne marchera pas, pourquoi? Je dois rater quelque chose. Le lien que vous envoyez indique "Pour émettre une requête asynchrone, votre application doit: ..." Et vous y trouverez également des instructions qui vous indiquent comment définir un délai d'expiration dans votre requête. Je ne peux pas exécuter le code google-api, mais cela me semble assez similaire. Pouvez-vous m'indiquer ce qui rend cette tâche impossible?


Désolé, je n'ai pas mentionné au départ que j'utilise Python 2.7. Et voici la confirmation que cela ne fonctionne pas - stackoverflow.com/questions/53719006/... .


Et qu'est-ce qui vous empêche d'utiliser l'extrait de code dans la réponse à ce message, ainsi que la date limite du paramètre urlfetch.create_rpc () indiqué dans le docs ?



0
votes

Hormis une expérience utilisateur douteuse - réponse lente et potentiellement pas la réponse attendue par vos utilisateurs - une telle approche pose un risque pour l'intégrité de votre serveur: pour chaque requête en attente, votre serveur utilisera des ressources et en cas de forte entrée Le pic des demandes peut s'exécuter sur son pool ou ses ressources disponibles (si elles sont limitées) ou peut augmenter vos coûts (par exemple en lançant des instances supplémentaires pour suivre les autres demandes entrantes s'il est configuré pour une mise à l'échelle automatique).

En général, pour les demandes qui peuvent prendre du temps, il est préférable de répondre immédiatement avec un identifiant de demande en attente et des URL complémentaires où le client peut vérifier l'état de la demande et éventuellement obtenir la réponse attendue, lorsqu'elle est disponible. Votre serveur prendrait soin - en arrière-plan, et non sur le thread de demande entrante d'origine - d'obtenir la réponse du serveur tiers. De cette façon, vous pouvez traiter tout type de demande qui peut prendre beaucoup de temps pour obtenir la réponse, que ce soit d'une tierce partie ou d'un traitement interne.


1 commentaires

Merci, Dan. Permettez-moi de vous donner plus de détails - je travaille sur le bot Voice Assistant (quelque chose de similaire à Google Assistant), où le bot doit répondre dans les 3 secondes. Et le bot ne peut pas lancer la réponse lui-même, c'est-à-dire que je ne peux pas donner une autre réponse, une fois la demande terminée. Et comme il s'agit d'un assistant vocal, je ne peux pas donner de lien. Je pensais à l'approche suivante - si je peux donner une réponse normale en 3 secondes, donnez-la. Sinon - demandez à l'utilisateur de demander à nouveau avec un mot simple comme "Statut".



0
votes

Parlez-vous à ce serveur tiers via http? pouvez-vous simplement utiliser le paramètre timeout dans les requêtes python?

class MainReply(webapp2.RequestHandler):
    def get(self):
        # do something
        try:
            r = requests.post(... , timeout=3)
            # finished, inform user
        except requests.exceptions.Timeout:
            # not finished, inform user


0 commentaires