Diciembre 30, 2014
enzo
Por lo general el Cron puede ser utilizado para ejecutar tareas que requieren una gran cantidad de procesamiento, es normal para ejecutar estas tareas sobre una lista de elementos.
El problema con estos requerimientos es que tal vez no es suficiente el tiempo de ejecución de un cron para procesar todos los elementos de nuestra lista de elementos a procesar. Así que tenemos que guardar el estado de ejecución y continuar la próxima vez que se ejecuta el cron.
Podemos hacer eso con Queues, pero esta solución es compleja de implementar (tal vez sólo para mí) así que voy a proponer una opción sencilla para implementar la función de reanudar el proceso.
- Trabajar con nuestra lista de elementos para procesar.
Imaginemos que almacenamos nuestra lista de elementos en un arreglo multi dimensional, y la opción normal parra procesar un arreglo en PHP está utilizando un foreach.
Bueno, no podemos utilizar un foreach para restaurar el proceso, porque esta función realiza un reset en al array al iniciar su ejecución establecimiento el puntero interno al primer elemento del array y lo que no es bueno para nuestro proceso de restaurar el proceso.
Así que debemos que usar una solución diferente para hacer eso, veamos como seria usando el foreach.
foreach ( $array as $array_key => $array_value ) {
}
a lo cual usaremos una solución alternativa, para evitar el reset.
while (list($array_key, $array_value) = each($array)) {
}
Usando While loop con algunos cambios podemos simular la asignación clave de la matriz en una variable que se puede hacer con un foreach.
- Guardar último estado
Con el problema del puntero del array resuelto, ahora necesitamos almacenar el último puntero correcto procesado por el cron. Para almacenar este valor voy a utilizar una nueva característica de Drupal Drupal::State().
Drupal:State funciona bien para almacenar information temporal y no crítica, esta información no se puede migrar entre los ambientes, por lo tanto no estará presente en el Configuration Management, si quieres saber mas de configuration management te invito a ver el video Entendiendo el modulo Configuration Management de Drupal 8
Déjenme mostrarles como usar el Drupal:State en combinación con los ciclos while.
while (list($array_key, $array_value) = each($array)) {
// --- INSERT LONG OPERATIONS HERE --
// Set last bank process to continue after this bank
\Drupal::state()->set('last_key', $array_key);
}
// Delete last bank if all were processed
\Drupal::state()->delete('last_key');
Al final del while usando el método set guardamos el ultimo valor procesado.
Si el hook_cron se interrumpe al menos sabremos en el último índice ejecutado sin problemas, ya que se almacena en la variable de estado last_key .
Si no recibimos ninguna interrupción debemos eliminar la variable de estado usando el método delete.
- Mover el puntero del Array.
Primero debemos crear una función personalizada llamada _array_set_pointer_by_key para establecer el puntero del array a cualquier posición arbitraria, déjenme enseñarle implementación.
function _array_set_pointer_by_key(&$array, $key)
{
reset($array);
while($index=key($array))
{
if($index==$key)
break;
next($array);
}
}
La función anterior funciona con cualquier tipo de indice de array.
Ahora debemos validar si tenemos que continuar con la ejecución de hook_cron en alguna posición de nuestro array, utilizando de nuevo el Drupal::State obtenemos la información como se puede ver en el siguiente fragmento de código.
$last_key = \Drupal::state()->get($last_bank_variable, null);
if ($last_key) {
// Set pointer to last key to process
_array_set_pointer_by_key($array, $last_key);
// Set array to next valid bank to process
next($array);
}
Después de restablecer el puntero del array a la posición deseada, usamos la función next para mover el puntero a la siguiente posición donde queremos reanudar.
Esta lógica la colocamos antes de la ejecución del while y así si quedo alguna tarea pendiente se continuare en la posición adecuada.
Espero que encuentre esta entrada del blog útil.