3 votes

PHP Curl Timeout plantant Javascript côté client

J'ai une synchronisation automatique qui envoie une requête CURL à un équipement et je fais cette requête pour chaque équipement que je possède (environ 60). Le problème est le suivant :
- Si la communication réussit, tout fonctionne bien.
- Mais si la communication échoue, la page web attendra que le délai d'attente soit écoulé. Donc le côté client se bloque pendant 3-4 minutes... J'ai des grilles importantes qui arrêtent de charger les données pendant ces 3-4 minutes.

La synchronisation automatique est une fonction en javascript qui fait une requête AJAX pour appeler le contrôleur php ci-dessous. Comment puis-je empêcher cela ? Je ne sais pas quoi essayer d'autre... L'AJAX est asynchrone, donc je ne comprends pas pourquoi la page web s'arrête.

Contrôleur :

$list = $panels_repository->getNetwork();

            $thread = new PollingThread($list);
            $thread->start();
            $thread->join();

            $result = $thread->result;
            $resultLength = sizeof($result);

            //...

Fil :

class PollingThread extends Thread {
private $panels_list;
private $alarm_status;
public $result;

public function __construct($list) {
    $this->panels_list = $list;
}

public function run() {
    $panels_list = $this->panels_list;

    $alarmsUpdated = array();
    $panels = array();

    foreach($panels_list as $panel) {
        $alarms_list = $panel->getAlarmsList();

        //Get updated alarms status
        $panel->getDiagnosticStatus($alarms_list);

        //Save the results
        array_push($alarmsUpdated, $alarms_list);
    }

    $this->result = $alarmsUpdated;

}  

getDiagnosticStatus

$input = "<?xml version='1.0' encoding='ISO-8859-1'?>
                <?getParameters message?>
                <displayMLRequest xmlns='http://www.peek.se/DisplayML/' version='1.12'
                                  dateTime='2008-01-10T15:09:51+02:00'>
                    <getParameters/>
                </displayMLRequest>";

    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $url); //Set IP to communicate

    //Set POST XML Input
    curl_setopt( $ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $input);

    //Return response as string & TimeOuts
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);

    //Execute
    $output = curl_exec($ch); 

    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    curl_close($ch);  

Javascript :

    $('#stations_tree').on('changed.jstree', function (e, data) {
    //....

    var dataObject = {
        type: "Selected",
        childrenID: childrenID_array,
        parentsID: parentsID_array
    };

    $.ajax({
        type: "POST",
        url: "controllers/PanelsController/",
        data: dataObject,
        cache: false,
        success: function ()
        {
            $("#dg_selected_stops").jsGrid("loadData");
            $("#dg_selected_pids").jsGrid("loadData");
        }
    });

}).jstree({
    plugins: ["checkbox", "state", "types"],
    "types": {
        "default": {
            "icon" : false
        }
    },
    core: {
        data: {
            url: "json/stations.json",
            dataType: "json",
            success: function () {
                //Save Panels Network as session variable
                var dataObject = {
                    type: "Network"
                };

                $.ajax({
                    type: "POST",
                    url: "controllers/PanelsController/",
                    data: dataObject,
                    cache: false,
                    success: function() {
                        //Get EquipmentStatus for each panel
                        var dataType = {
                            type: "Save"
                        };

                        $.ajax({
                            type: "POST",
                            url: "controllers/EquipmentStatusController/",
                            data: dataType,
                            cache: false,
                            success: function () {
                                //Status Unknown
                                changeTreeIcons();
                                loadAlarmsData();

                                polling();
                            }
                        });   
                    }
                });
            }
        }
    }
});

Fonction polling() - Où le JS s'arrête jusqu'à ce que le délai d'attente soit écoulé.

function polling() {
var dataObject = {
    type: "Polling",
};

$.ajax({
    type: 'POST',
    url: "controllers/DatabaseController/",
    data: dataObject,
    success: function(response) {
        //loadAlarmsData();
        //changeTreeIcons();
    }
});

}

EDIT : J'ai vérifié que si j'essaie de faire une requête AJAX après que le sondage ait commencé, la page web ne fait cette requête qu'après que le php script soit terminé. Donc le JS qui bloque sont des tables qui chargent des données avec des requêtes ajax. Comment puis-je résoudre ce problème ?

2voto

Alex K Points 392

Ce n'est pas une solution complète pour le copier/coller, mais cela peut vous donner une idée de la façon de résoudre votre problème. Vous pouvez essayer le suivant (php-fpm seulement).

Du côté frontal, exécutez la synchronisation en utilisant des js et appelez votre contrôleur, du côté client, dans le contrôleur, envoyez la réponse pour le navigateur et appelez fastcgi_finish_request() avant que votre opération CURL ne démarre. Cette fonction vide toutes les données de réponse vers le client et termine la requête, mais PHP script continue le travail.

...

$list = $panels_repository->getNetwork();

$key = 'my_unique_operation_key'; // it key need you for get data on client side
$resp = [
   'status'=>'start',
   'operation_key' => $key
];
echo json_encode($resp);
fastcgi_finish_request(); // close connection and continue ...

$thread = new PollingThread($list, $key); // send $key also
...

Dans PollingThread :

...
foreach($panels_list as $panel) {
    $alarms_list = $panel->getAlarmsList();

    //Get updated alarms status
    $panel->getDiagnosticStatus($alarms_list);

    //Save the results
    array_push($alarmsUpdated, $alarms_list);

    ...
    // save operation progress for example in memcache
    $progressData = some data about progress and $alarmsUpdated, etc...
    $memcache_obj->set('operation_'.$key, json_encode($progressData));
}

Quelque part dans le contrôleur, ajoutez une action qui renvoie des parties de données :

function getDataPartially_action(){
  $key = $_GET['key']; // not forget validate
  ...
  $jsonData = $memcache_obj->get('operation_'.$key);  // get current state from memcache by key
  echo $jsonData;
  exit();
}

Du côté frontal :

// call controller and start operation
$.ajax({
  url: '/controller/uri/here',
  beforeSend: function() {
    // here you can place spinner or progress bar ...
  },
  success: function(json) {
    // in json you get progress key after fastcgi_finish_request()
    // and run visual progress
    getDataPartially(key);
  }
});

// load data partially
function getDataPartially(key){
  var timerId = setInterval(function() {
    $.ajax({
      url: '/controller/uri/here/getDataPartially_action?key=' + key,      
      success: function(json) {
        // in json you have data for grids and progress info
        // if json contains finish info stop progress
        clearInterval(timerId);
        // hide progress bar and etc ...
    }
});}, 2000);
}

p.s. Dans la fonction CURL, vous pouvez utiliser FONCTION CURLOPT_PROGRESS et obtenir plus d'informations sur les progrès réalisés :

$ch = curl_init();
    curl_setopt ...
    curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, 'curl_progress_callback');
    ...
// where curl_progress_callback is:

    function curl_progress_callback($dltotal, $dlnow, $ultotal, $ulnow){
        $curlInfo = curl_getinfo($ch); // a lot info about connection
        echo $curlInfo['connect_time'];
        echo $curlInfo['http_code'] ...      
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X