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:

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

En este caso es un bucle infinito, pero eso ahora no importa, el [crayon lang=»php» inline=»true»]sleep($interval);[/crayon] es el tiempo de espera entre dos ejecuciones del bucle… pero podemos encontrarnos con que si [crayon lang=»php» inline=»true»]$interval = 300;[/crayon] (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:

<?php
  $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:

<?php
  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:

<?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 <= strtotime('+1sec')) {
      $time_start = strtotime('+1day', $time_start);
      $time_end = strtotime('+1day', $time_end);
      $next = $time_start;
    }
    while ($next <= strtotime('+1sec')) $next = strtotime($interval, $next);
    echo date('Y-m-d H:i:s', $next), HT, 'next', "\n";
    while (time() < $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.

Compártelo

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *