Jump to content

Edit History

Prestafan33

Prestafan33

Por lo que dices entonces el problema no es la duración del proceso PHP, sino que se satura el número de conexiones abiertas con la base de datos. Si lo que haces es comprobar, para cada producto, si ya existe en la base de datos, seguramente el problema esté ahí, cada comprobación abre una conexión nueva con la base de datos, y llega un momento en que el número de ellas disponibles se agota.

No sé cómo estás haciendo exactamente el proceso de inserción masiva de productos, pero te cuento cómo he afrontado yo los problemas de timeout al generar un feed de productos de Prestashop con varios miles de productos:

Lo que hago básicamente es, para evitar agotar el tiempo de los scripts PHP, ir contando el número de productos que proceso. Cuando llego a una cantidad establecida (por ejemplo, 500 productos), lo que hago es que el controlador se vuelva a llamar a sí mismo pasando el número del último producto que se ha procesado. De este modo, cuando esa variable está presente en la llamada, se salta directamente a ese último producto y se continúa desde ahí, sin tener que hacer más comprobaciones ni consultas a la base de datos. Lo explico con un poco de código:

public function initContent() {
  if (Tools::isSubmit('action')) {
    $action = Tools::getValue('action');
    switch ($action) {
      case 'generateFeed':
        $continue = 0;
        if (Tools::isSubmit('continue') && ctype_digit(Tools::getValue('continue'))) {
          $continue = (int)Tools::getValue('continue');
        }
        $this->generateFeed($continue);
        break;
    }
  }
}

[...]

// Procesando los productos...
protected function generateFeed($continueFrom=0) {
  $products = $this->getAllProductsInDatabase($continueFrom, $this->numberProductsToProcess);
  /* Aquí recupero los productos a procesar, A PARTIR DEL NÚMERO DE PRODUCTO RECIBIDO EN LA ÚLTIMA LLAMADA ($continueFrom).
  En "numberProductsToProcess" tengo el número de productos a procesar en cada llamada (por ejemplo, 500).*/
  $numberProductsProcessed = 0;
  foreach($products as $p) {
    $this->processProduct($p);
    if ($this->numberProductsToProcess <= ++$numberProductsProcessed) {
      $this->makeContinueAsyncronousCall($continueFrom + $numberProductsProcessed + 1);
    }
  }
}
      
[...]
      
// Finalmente, uso CURL para llamar de nuevo al controlador y que continúe la importación a partir del último producto procesado
protected function makeContinueAsyncronousCall($nextProductToProcess){
  $url = Tools::getHttpHost(true).__PS_BASE_URI__.'module/'.$this->module->name.'/feed?action=generateFeed&key='.$this->module->secret_key;
  $url.= '&continue='.$nextProductToProcess;  // Aquí uso la URL de mi módulo y le paso por GET la variable "continue" con el número del siguiente producto a procesar
  $curl = curl_init();                
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_USERAGENT, 'api');
  curl_setopt($curl, CURLOPT_TIMEOUT, 2); 
  curl_setopt($curl, CURLOPT_HEADER, 0);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
  curl_setopt($curl, CURLOPT_FORBID_REUSE, true);
  curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2);
  curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT, 10); 
  curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    
  curl_exec($curl);
  $result = curl_getinfo($curl);
  curl_close($curl);
}

 

Prestafan33

Prestafan33

Por lo que dices entonces el problema no es la duración del proceso PHP, sino que se satura el número de conexiones abiertas con la base de datos. Si lo que haces es comprobar, para cada producto, si ya existe en la base de datos, seguramente el problema esté ahí, cada comprobación abre una conexión nueva con la base de datos, y llega un momento en que el número de ellas disponibles se agota.

No sé cómo estás haciendo exactamente el proceso de inserción masiva de productos, pero te cuento cómo he afrontado yo los problemas de timeout al generar un feed de productos de Prestashop con varios miles de productos:

Lo que hago básicamente es, para evitar agotar el tiempo de los scripts PHP, ir contando el número de productos que proceso. Cuando llego a una cantidad establecida (por ejemplo, 500 productos), lo que hago es que el script se vuelva a llamar a sí mismo pasando el número del último producto que se ha procesado. De este modo, cuando esa variable está presente en la llamada, se salta directamente a ese último producto y se continúa desde ahí, sin tener que hacer más comprobaciones ni consultas a la base de datos. Lo explico con un poco de código:

if (Tools::isSubmit('action')) {
  $action = Tools::getValue('action');
  switch ($action) {
    case 'generateFeed':
      $continue = 0;
      if (Tools::isSubmit('continue') && ctype_digit(Tools::getValue('continue'))) {
        $continue = (int)Tools::getValue('continue');
      }
      $this->generateFeed($continue);
      break;
  }
}

[...]

// Procesando los productos...
protected function generateFeed($continueFrom=0) {
  $products = $this->getAllProductsInDatabase($continueFrom, $this->numberProductsToProcess);
  /* Aquí recupero los productos a procesar, A PARTIR DEL NÚMERO DE PRODUCTO RECIBIDO EN LA ÚLTIMA LLAMADA ($continueFrom).
  En "numberProductsToProcess" tengo el número de productos a procesar en cada llamada (por ejemplo, 500).*/
  $numberProductsProcessed = 0;
  foreach($products as $p) {
    $this->processProduct($p);
    if ($this->numberProductsToProcess <= ++$numberProductsProcessed) {
      $this->makeContinueAsyncronousCall($continueFrom + $numberProductsProcessed + 1);
    }
  }
}
      
[...]
      
// Finalmente, uso CURL para llamar de nuevo al controlador y que continúe la importación a partir del último producto procesado
protected function makeContinueAsyncronousCall($nextProductToProcess){
  $url = Tools::getHttpHost(true).__PS_BASE_URI__.'module/'.$this->module->name.'/feed?action=generateFeed&key='.$this->module->secret_key;
  $url.= '&continue='.$nextProductToProcess;  // Aquí uso la URL de mi módulo y le paso por GET la variable "continue" con el número del siguiente producto a procesar
  $curl = curl_init();                
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_USERAGENT, 'api');
  curl_setopt($curl, CURLOPT_TIMEOUT, 2); 
  curl_setopt($curl, CURLOPT_HEADER, 0);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
  curl_setopt($curl, CURLOPT_FORBID_REUSE, true);
  curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2);
  curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT, 10); 
  curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    
  curl_exec($curl);
  $result = curl_getinfo($curl);
  curl_close($curl);
}

 

Prestafan33

Prestafan33

Por lo que dices entonces el problema no es la duración del proceso PHP, sino que se satura el número de conexiones abiertas con la base de datos. Si lo que haces es comprobar, para cada producto, si ya existe en la base de datos, seguramente el problema esté ahí, cada comprobación abre una conexión nueva con la base de datos, y llega un momento en que el número de ellas disponibles se agota.

No sé cómo estás haciendo exactamente el proceso de inserción masiva de productos, pero te cuento cómo he afrontado yo los problemas de timeout al generar un feed de productos de Prestashop con varios miles de productos:

Lo que hago básicamente es, para evitar agotar el tiempo de los scripts PHP, ir contando el número de productos que proceso. Cuando llego a una cantidad establecida (por ejemplo, 500 productos), lo que hago es que el script se vuelva a llamar a sí mismo pasando el número del último producto que se ha procesado. De este modo, cuando esa variable está presente en la llamada, se salta directamente a ese último producto y se continúa desde ahí, sin tener que hacer más comprobaciones ni consultas a la base de datos. Lo explico con un poco de código:

if (Tools::isSubmit('action')) {
  $action = Tools::getValue('action');
  switch ($action) {
    case 'generateFeed':
      $continue = 0;
      if (Tools::isSubmit('continue') && ctype_digit(Tools::getValue('continue'))) {
        $continue = (int)Tools::getValue('continue');
      }
      $this->generateFeed($continue);
      break;
  }
}

[...]

// Procesando los productos...
protected function generateFeed($continueFrom=0) {
  $products = $this->getAllProductsInDatabase($continueFrom, $this->numberProductsToProcess);
  /* Aquí recupero los productos a procesar, A PARTIR DEL NÚMERO DE PRODUCTO RECIBIDO EN LA ÚLTIMA LLAMADA ($continueFrom).
  En "numberProductsToProcess" tengo el número de productos a procesar en cada llamada (por ejemplo, 500).*/
  $numberProductsProcessed = 0;
  foreach($products as $p) {
	$this->processProduct($p);
    if ($this->numberProductsToProcess <= ++$numberProductsProcessed) {
      $this->makeContinueAsyncronousCall($continueFrom + $numberProductsProcessed + 1);
    }
  }
}
      
[...]
      
// Finalmente, uso CURL para llamar de nuevo al controlador y que continúe la importación a partir del último producto procesado
protected function makeContinueAsyncronousCall($nextProductToProcess){
  $url = Tools::getHttpHost(true).__PS_BASE_URI__.'module/'.$this->module->name.'/feed?action=generateFeed&key='.$this->module->secret_key;
  $url.= '&continue='.$nextProductToProcess;  // Aquí uso la URL de mi módulo y le paso por GET la variable "continue" con el número del siguiente producto a procesar
  $curl = curl_init();                
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_USERAGENT, 'api');
  curl_setopt($curl, CURLOPT_TIMEOUT, 2); 
  curl_setopt($curl, CURLOPT_HEADER, 0);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
  curl_setopt($curl, CURLOPT_FORBID_REUSE, true);
  curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2);
  curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT, 10); 
  curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    
  curl_exec($curl);
  $result = curl_getinfo($curl);
  curl_close($curl);
}

 

×
×
  • Create New...