10
votes

Comment puis-je faire du délai d'expiration de php gracieusement en attendant des requêtes MySQL à long terme?

J'ai un site PHP qui exécute beaucoup de questions de base de données. Avec certaines combinaisons de paramètres, ces requêtes peuvent finir de fonctionner pendant une longue période, déclenchant un message de délai de délai laide. Je veux remplacer cela par un beau message de délai d'attente en fonction du reste du style de mon site.

Anticiper les réponses habituelles à ce type de question:

  1. "Optimisez vos requêtes afin qu'ils ne fonctionnent pas depuis si longtemps" - je vous enregistre des requêtes à long terme et les optimiser, mais je ne sais que sur ceux-ci après l'affectation d'un utilisateur. < / li>

  2. "Augmentez votre réglage de délai d'attente PHP (E.G. Set_Time_Limit, max_execution_time) afin que la requête à long terme puisse finir» - Parfois, la requête peut fonctionner pendant plusieurs minutes. Je veux dire à l'utilisateur qu'il y a un problème avant cela (par exemple 30 secondes).

  3. "Utilisez registre_tick_function pour surveiller la manière dont les scripts longs sont en cours d'exécution" - ce n'est exécuté qu'entre les lignes de code dans mon script. Pendant que le script attend une réponse de la base de données, la fonction de tick ne s'appelle pas.

    Si cela aide, le site est construit à l'aide de Drupal (avec beaucoup de personnalisation) et est en cours d'exécution sur un serveur Linux dédié virtuel sur PHP 5.2 avec MySQL 5.


0 commentaires

3 Réponses :


0
votes

Le Manipulation de la connexion Docs est ce dont vous avez besoin.

Fondamentalement, vous devez enregistrer une fonction d'arrêt à l'aide de Register_shutdown_function () . Cette fonction sera appelée chaque fois qu'un script est terminé, que cela soit terminé avec succès, a été annulé par l'utilisateur (clé US) ou a expiré.

Cette fonction d'arrêt peut alors appeler le Connection_Status () fonction. Si Connection_Status () renvoie 2 (délai d'attente) et la page précédente était celle qui exécute la requête gênante, vous pouvez rediriger l'utilisateur à une page indiquant "Désolé, mais nous vivons une charge de serveur haute en ce moment." / em> ou autre chose.


5 commentaires

TIS ne concerne que la connexion entre l'endroit où le code PHP est exécuté (généralement un serveur Web) et un navigateur - pas le serveur Web et le SGBD


Il ne demande pas quelque chose qui communique avec le SGBD, juste un mécanisme permettant de manipuler des délais de script gracieusement, ce que Connection_Status () a été conçu pour faire. J'ai édité ma réponse pour fournir plus d'informations.


Cela ressemble à la solution dont j'ai besoin, mais je me débats avec la redirection. J'essaie d'utiliser la fonction PHP Header (), mais cela dit que les en-têtes ont déjà été envoyés. Même avec un cas de test simple: set_time_limit (1); registre_shutdown_function ('clean_shutdown'); tandis que (vrai) {} fonction propre_shutdown () {if (Connection_Status () & Connection_Timeout) {ob_end_clean (); Header ('Emplacement: BBC.CO.UK ', vrai, 500); }} Je reçois toujours un message "en-têtes déjà envoyé (à la ligne 5)", mais je ne vois pas où ils auraient été envoyés.


BTW, ignorer les backtsks dans cette extrait de code - je me rends toujours à des poignées avec Markdown, et je ne me laisserai donc plus le modifier!


9 fois sur 10, cette erreur indique que vous avez déjà commencé à émettre une réponse d'une sorte. Il ne doit pas nécessairement être un élément HTML ou une déclaration ECHO. Même un caractère de blanchisson dans votre document déclenchera les en-têtes à envoyer. J'ai déjà eu cette erreur parce que la première ligne de mon script a lu: " php.net/manual/fr/function.Header.php#95864



3
votes

Il n'y a pas d'appels mysql asynchrones et aucune étendue de filetage léger.

Bien que vous puissiez diviser votre code PHP en deux niveaux et utiliser une connexion entre eux que vous pouvez invoquer de manière asynchrone, le problème avec cette approche est que le niveau de la DB essaiera d'exécuter la requête après que le niveau supérieur ait abandonné Les résultats en arrière - bloquent potentiellement le SGBD pour d'autres utilisateurs. (Vous êtes plus susceptible d'obtenir des demandes plus fréquentes pour les pages chronométrées).

Vous aurez le même problème si vous poussez le délai d'attente de manipulation dans un proxy inverse assis devant le serveur Web.

L'endroit le plus sensible pour mettre en œuvre le délai d'attente est la base de données elle-même - mais Afaik, MySQL ne supporte pas cela.

Alors l'option suivante construit un proxy entre le PHP et la base de données - cela pourrait être autonome - générer 2 fils léger pour chaque requête (1 pour exécuter la requête, 2e sous forme de chien de garde pour tuer le premier s'il faut aussi Long) - mais cela nécessite non seulement un code d'écriture dans une lnaguage qui soutient des fils légers, mais définissant également un protocole de communication avec le PHP.

Toutefois, prenant une approche différente du modèle de proxy - vous pouvez accéder à un processus PHP distinct à l'aide de proc_open et définissez le flux STDOUT pour être non bloquant - de cette façon que votre PHP puisse continuer à fonctionner et à vérifier si le proxy a fonctionné. la requête. Si cela est terminé, alors comme le parent du proxy, il peut le signaler à l'arrêt (proc_terminate ()) qui devrait arrêter la requête en cours d'exécution sur la base de données.

Certainement, ça va vouloir dire beaucoup de travail de développement.

Cela peut prouver beaucoup plus simple pour configurer un ou plusieurs SGBD esclaves pour exécuter vos requêtes lentes contre - potentiellement avec un équilibrage de la charge intelligente. Ou regarder d'autres moyens de faire des requêtes lentes aller plus vite - comme la pré-consolidation.

htth

c.


0 commentaires

-1
votes

Votre serveur est-il accordé avec APC, MemCache, Boost et Drupal Cache? Ce sont des voies alternatives qui fonctionnent très bien.

Sinon, quel type de scripts fonctionnent dans Drupal qui causerait cela? Juste hors de curiosité, faites-vous des vues et des panneaux?


1 commentaires

Ce n'est pas une question drupale. Nous utilisons des vues et des panneaux, mais pas sur cette partie du site. (Je sais que les modules seront toujours chargés, mais nous ne les appelons pas). Le problème ici est exclusivement accès à la base de données, et il s'agit de requêtes spécifiques au client qui causent le problème. Certains clients ont plus de données que d'autres et certains demandent-ils plus de périodes plus longues que d'autres. J'ai déjà créé des tables de synthèse pour accélérer de nombreuses questions, mais il reste encore du travail à faire. Je cherche quelque chose pour fournir une expérience utilisateur plus propre pendant que ce travail se passe.