Trabajos cron y tiempos aleatorios, dentro de horas determinadas

100

Necesito la capacidad de ejecutar un script PHP 20 veces al día en momentos completamente aleatorios. También quiero que se ejecute solo entre las 9 a.m. y las 11 p.m.

Estoy familiarizado con la creación de trabajos cron en Linux.

flotador izquierdo
fuente
1
La pregunta no está muy bien planteada. En última instancia, desea distribuir 20 puntos en el eje del tiempo entre las 9 a. M. Y las 11 a. M. Pero, ¿existen restricciones sobre la diferencia horaria mínima? ¿Es aceptable no hacer nada entre las 9 a. M. Y las 10:30 a. M.? La única forma de hacer esto de manera aceptable parece ser la idea de Klaus: seleccione sus 20 horas a las 09:00, lo que le permite cumplir con cualquier restricción que pueda tener, luego programe las cosas con "en".
David Tonhofer

Respuestas:

38

Si entiendo lo que está buscando, tendrá que hacer algo un poco complicado, como tener un trabajo cron que ejecuta un script bash que aleatoriza los tiempos de ejecución ... Algo como esto:

crontab:

0 9 * * * /path/to/bashscript

y en / ruta / a / bashscript:

#!/bin/bash

maxdelay=$((14*60))  # 14 hours from 9am to 11pm, converted to minutes
for ((i=1; i<=20; i++)); do
    delay=$(($RANDOM%maxdelay)) # pick an independent random delay for each of the 20 runs
    (sleep $((delay*60)); /path/to/phpscript.php) & # background a subshell to wait, then run the php script
done

Algunas notas: este enfoque es un poco desperdicio de recursos, ya que dispara 20 procesos en segundo plano a las 9 a.m., cada uno de los cuales espera un número aleatorio de minutos (hasta 14 horas, es decir, 11 p.m.), luego inicia el script php y salidas. Además, dado que usa un número aleatorio de minutos (no segundos), las horas de inicio no son tan aleatorias como podrían ser. Pero $ RANDOM solo sube a 32,767, y hay 50,400 segundos entre las 9 am y las 11 pm, sería un poco más complicado aleatorizar los segundos también. Finalmente, dado que las horas de inicio son aleatorias e independientes entre sí, es posible (pero no muy probable) que dos o más instancias del script se inicien simultáneamente.

Gordon Davisson
fuente
2
Puede hacer que las asignaciones aritméticas sean más legibles dejando caer el signo de dólar y moviendo los pares dobles hacia la izquierda (por ejemplo, ((maxdelay = 14 * 60))o ((delay = $RANDOM % maxdelay))). El sleepargumento aún debe ser como lo tiene (aunque puede agregar espacios, si lo desea).
Pausado hasta nuevo aviso.
Esto funcionó para mí también. Mi script de bash personalizado se ve a continuación sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
Shyam Habarakada
¿Me estoy perdiendo algo o la demora máxima debe establecerse en maxdelay = $ ((14 *
60/20
@jenishSakhiya Los retrasos aleatorios para cada una de las 20 carreras son absolutos (bueno, a partir de las 9 am), no relativos a otra de las carreras. Es decir, si uno de los retrasos aleatorios es de 13 horas, eso significa que se ejecutará a las 10 p.m. (13 horas después de las 9 a.m.), no 13 horas después de cualquiera de las otras ejecuciones.
Gordon Davisson
138

Sí, sí, la pregunta tiene más de un año, pero tal vez pueda agregar algo útil:

¿Cómo cronometrar algo con un desplazamiento aleatorio 20 veces al día entre las 9 a.m. y las 11 p.m.? Eso es un poco complicado dentro de cron, porque estás dividiendo 14 horas entre 20 tiempos de ejecución. No me gustan mucho las otras respuestas porque requieren escribir un script bash wrapper para su script php.

Sin embargo, si me permite la libertad de facilitar la restricción de tiempo y frecuencia a 13 veces entre las 8:30 am y las 11:09 pm, esto podría funcionar, y todo dentro de los límites de su crontab:

30 8-21/* * * * sleep ${RANDOM:0:2}m ; /path/to/script.php

$ {RANDOM: 3: 2} usa $ RANDOM de bash que otras personas han mencionado anteriormente, pero agrega la división de matrices de bash. Dado que las variables de bash no están tipificadas, el número de 16 bits con signo pseudoaleatorio se trunca a los primeros 2 de sus 5 dígitos decimales, lo que le brinda una breve línea para retrasar su cronjob entre 10 y 99 minutos (aunque la distribución está sesgada hacia 10 a 32).

Lo siguiente también podría funcionar para usted, pero descubrí que es "menos aleatorio" por alguna razón (quizás la Ley de Benford se activa al modular números pseudoaleatorios. Oye, no sé, fallé en matemáticas ... en bash!):

30 8-21/* * * * sleep $[RANDOM\%90]m ; /path/to/script.php

Necesita representar el módulo como '\%' arriba porque cron (bueno, al menos Linux 'vixie-cron') termina la línea cuando encuentra un '%' sin escape.

Tal vez podría obtener las 7 ejecuciones de script restantes allí agregando otra línea con otro rango de 7 horas. O relaje su restricción para correr entre las 3 am y las 11 pm.

al-x
fuente
4
Me gusta la respuesta tardía. Pero si está tratando de generar un número entero aleatorio distribuido uniformemente en el rango de 10 a 99, y la salida de RANDOM es de 0 a 32,767, ¿por qué no lo haría $[(RANDOM/368)+10]?
jsdalton
3
@jsdalton: ¿No sería mejor el operador de módulo? $((RANDOM % 90 + 10))Prueba:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
geon
5
En muchos sistemas de cron no utiliza bash por defecto por lo que podría ser mejor para evitar la del bash $RANDOM: sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m.
pabouk
9
Asegúrese de crontabusarlo bashantes de usarlo $RANDOM. Si lo tiene vixie-cron(parece ser mi caso en Ubuntu), puede agregarlo SHELL=/bin/basha la parte superior. Hay más alternativas para otras versiones de cron aquí: superuser.com/a/264541/260350
DaAwesomeP
1
Cuando utilizo la primera sugerencia anterior, recibo crontab: errors in crontab file, can't install. Do you want to retry the same edit?ayuda
Seano
72

Entonces estoy usando lo siguiente para ejecutar un comando entre 1AM y 330AM

0 1 * * * perl -le 'sleep rand 9000' && *command goes here*

Eso se ha ocupado de mis necesidades al azar por mí. Eso es 9000 segundos == 150 minutos == 2.5 horas

Dave
fuente
8
:: MindBLOWN :: otro lugar oscuro para usar un poco de perl.
Mark Carpenter Jr
Esta es definitivamente la respuesta más limpia
Enrico Detoma
Sin embargo, esto es algo ineficiente, ya que está creando muchos procesos.
kahveciderin
21

Cron ofrece una RANDOM_DELAYvariable. Consulte crontab(5)para obtener más detalles.

La variable RANDOM_DELAY permite retrasar el inicio de trabajos por una cantidad aleatoria de minutos con un límite superior especificado por la variable.

Esto se ve comúnmente en anacrontrabajos, pero también puede ser útil en a crontab.

Es posible que deba tener cuidado con esto si tiene algunos trabajos que se ejecutan con una granularidad fina (minuto) y otros que son gruesos.

Micah Elliott
fuente
Me encantaría usar la variable RANDOM_DELAY, pero no puedo encontrar ninguna pista en la página de manual de crontab (5) en Ubuntu 14.04.4 LTS.
Exocom
Eso es lamentable. Me pregunto si no es compatible allí. Lo veo documentado en esa página de manual de Centos 7 y Arch Linux.
Micah Elliott
9
esta parece la respuesta correcta, pero ¿puede poner un ejemplo?
chovy
14
Tenga en cuenta que RANDOM_DELAYse establece una vez y permanece constante durante todo el tiempo de ejecución del demonio.
Maciej Swic
5
La RANDOM_DELAYbandera es una característica de cronie-crond mientras que Ubuntu parece estar ejecutándose vixie-crony carece de esta bandera.
Kravietz
7

Mi primer pensamiento sería crear un trabajo cron lanzando 20 trabajos programados al azar. La atutilidad (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) se utiliza para ejecutar comandos en el momento especificado.

Klaus
fuente
Un ejemplo de uso de at está aquí: stackoverflow.com/a/6136145/803174
Kangur
6

Terminé usando sleep $(( 1$(date +%N) % 60 )) ; dostuffs(compatible con bash & sh)

El prefijo 1 es para forzar una interpretación NO base 8 de la fecha +% N (por ejemplo, 00551454)

No olvide escapar% usando \% en un archivo crontab

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 
131
fuente
2
Si alguien se pregunta, como yo:% N proporciona nanos actuales, pero algunas páginas de manual carecen de información al respecto. Esta es una solución muy inteligente para personas que solo necesitan "algo de aleatoriedad" fácilmente por comando.
Thorsten Schöning
Aparte de las advertencias ya cubiertas en otro lugar, esto solo funcionará si tiene GNU date(lo que probablemente lo haga en la mayoría de los Linux, pero no en Busybox, MacOS estándar o varias otras plataformas derivadas de BSD).
triplicado
4

La solución de al-x no me funciona ya que los comandos crontab no se ejecutan en bash sino en sh, supongo. Lo que funciona es:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py
Wilbert
fuente
Probé todo y todavía no me funcionó. Publicaste explicado por qué, ¡gracias!
marlar
$[ ... ]está en desuso la sintaxis desde waaaay atrás; para cualquier cosa de este milenio, preferiría $((RANDOM\%90))mque sea una sintaxis compatible con POSIX (pero, por supuesto, RANDOMsigue siendo solo Bash).
triplicado
1

at -f [file] [timespec]

o

echo [command] | at [timespec]

o

at [timespec]... y especificación interactiva como scriptla grabación.

Mando

En se ejecuta el texto provide en stdin o en el archivo especificado por -f [file].

Timespec

Aquí está la [timespec] gramática . Puede ser algo como:

  • 24 horas como int de 4 dígitos, p 0100. Ej . 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

Si especifica explícitamente la zona horaria, es posible que algunas versiones de la especificación de tiempo solo permitan UTCel argumento de zona horaria opcional.

Ejemplo

cat script.sh | at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Pruébalo...

Puede probar el análisis de bash pre-pendiente echoy escapando del |(pipe).

echo cat script.sh \| at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

echo at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Para ver los trabajos programados, use atqy el contenido del trabajo (variables de entorno, configuración y comando / script) con at -c [jobid].

Nota

El sistema es parte de cron, y el indicador interactivo realmente captura todo el estado actual de su shell, por lo que puede ejecutar comandos sin especificar rutas absolutas.

mcint
fuente
0

Para aquellos que buscaron en Google el camino aquí:

Si está utilizando anacron (Ubuntu de escritorio y portátil), puede editar

/etc/anacrontab

y añadir

RANDOM_DELAY=XX 

Donde XX es la cantidad de minutos que desea retrasar el trabajo base.

Anacron es como cron, pero no espera que su computadora esté en funcionamiento las 24 horas, los 7 días de la semana (como nuestras computadoras portátiles) y ejecutará los scripts que omitió porque el sistema no funcionaba.

Ganesh Krishnan
fuente
0

Puede intentar con este ejemplo usar tiempos aleatorios antes de ejecutar el comando:

#!/bin/bash
# start time
date +"%H:%M:%S"

# sleep for 5 seconds
sleep $(shuf -i 1-25 -n 1)
# end time
date +"%H:%M:%S"
Houssin Boulla
fuente
0

¿Qué tal crear un script que reescriba el crontab todos los días?

  1. Leer crons actuales (A)
  2. Elija momentos aleatorios (B)
  3. Reescribir crons anteriores (A), agregar nuevos crons aleatorios (B)
  4. Asegúrese de agregar al cron para ejecutar este script en primer lugar.
meloso
fuente
2
No eluda el sistema de reputación publicando comentarios como respuestas. Sin embargo, su comentario se ve lo suficientemente bueno como para ser una respuesta. Recomiendo eliminar " No tengo representante para agregar un comentario, pero ".
Ted Lyngmo
1
Acabo de revisar esta respuesta y me perdí la parte en la que haces una pregunta a cambio al final (trabajo descuidado de mi parte). No hagas preguntas en las respuestas. Publique su propia pregunta para las preguntas que tenga. Convertí tu semi-pregunta en algo que podría pasar por una respuesta.
Ted Lyngmo
1
¡Entendido! Gracias. Tendré más cuidado la próxima vez, no pretendía ninguna mala intención
mellofellow
1
Estoy seguro de que no tuvo malas intenciones y no necesita ser demasiado cuidadoso. Esbozó una posible solución y tropezó un poco al final. ¡Sin preocupaciones!
Ted Lyngmo
0

Me doy cuenta de que es un hilo más antiguo, pero quiero agregar una cosa relacionada con el valor aleatorio que uso mucho. En lugar de usar la variable $ RANDOM con un rango fijo y limitado, a menudo hago valores aleatorios de rango arbitrario en el shell con

dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none

para que puedas hacer, por ejemplo,

FULLRANDOM=$(dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none)

y superar algunas de las restricciones que se discutieron en este hilo.

MLP
fuente
1
Bienvenido a SO. Bueno, hilo viejo o no, esto me envió a ~$info ddy puedo entender lo que está pasando en el lado izquierdo |, pero no puedo distinguir el lado derecho. Entonces, para mí y para otros interesados ​​enovercoming some restrictions la generación de valores aleatorios, ¿por qué no tomarse un momento para explicar el RHS y hacer un discurso más fuerte para usar su enfoque? La profundidad de la explicación hace que las personas se sientan cómodas con el proceso que sugiere y sus beneficios. Gracias.
Chris
Ah ok. od también conocido como "volcado octal" toma un archivo o stdin y vuelca los datos binarios en forma legible por humanos. Queremos que nuestro número se muestre como un decimal sin signo (-t u4), y no queremos el índice de dirección (-A ninguno). El -N4 es redundante ya que solo usamos 4 bytes, pero tampoco duele. Espero que esto lo explica ...
MLP