Programar una espera hasta un momento determinado

En ocasiones necesitamos que un script realice una tarea determinada cada cierto tiempo o a partir de un momento (fecha/hora) determinados.

En linux es fácil realizar esto mediante cron, sin embargo el programador de tareas de Windows es más farragoso de configurar para estos menesteres. Además puede que no nos interese/guste que el script esté continuamente arrancando/parando.

Hasta ahora realizaba este tipo de bucles para estas tareas:

do {
  // anything
  sleep($interval);
} while (true);

En este caso es un bucle infinito, pero eso ahora no importa, el sleep($interval); (línea 3) es el tiempo de espera entre dos ejecuciones del bucle… pero podemos encontrarnos con que si $interval = 300; (segundos) luego a la hora de la verdad se nos irá añadiendo algún segundo que otro entre las ejecuciones del bucle… y esto puede no importar o todo lo contrario.

Ayer encontré una función maravillosa: time_sleep_until()

Tal y como dice la documentación esta función dejará el script en pausa hasta que llegue el momento determinado en la función:

$next = time();
do {
  // anything
  $next = strtotime('+5min', $next);
  time_sleep_until($next);
} while (true);

El problema es que según parece esta función trabaja en microsegundos, y guarda el valor con un entero de 32 bits, lo que nos da un máximo de 2^32 microsegundos, unos 4295 segundos (1 hora, 11 minutos y 35 segundos). Para solventar esto se me ha ocurrido la misma solución que la que apunta “purdue” en la documentación:

while (time() < $next) time_sleep_until($next);

Y bueno, juntando algunas cosas más podemos hacer que el script realice una tarea cada cierto tiempo durante unas horas al día:

&lt;?php
  $runfile = 'runfile.log';
  $interval = '5min';
  $start = '18:00:00';
  $end = '22:00:00';

  $time_start = strtotime($start);
  $time_end = strtotime($end);
  $next = $time_start;

  do {
    file_put_contents($runfile, date('Y-m-d H:i:s')); 
    if ($time_end &lt;= strtotime('+1sec')) {
      $time_start = strtotime('+1day', $time_start);
      $time_end = strtotime('+1day', $time_end);
      $next = $time_start;
    }
    while ($next &lt;= strtotime('+1sec')) $next = strtotime($interval, $next);
    echo date('Y-m-d H:i:s', $next), HT, 'next', "\n";
    while (time() &lt; $next) time_sleep_until($next);
    // anything
  } while (file_exists($runfile));

En el ejemplo completo he hecho que el bucle se ejecute siempre y cuando exista un fichero “runfile”, cuando lo borremos el bucle se ejecutará una última vez y terminara.

Leave a Reply

Your email address will not be published. Required fields are marked *