Programe el comando para que se ejecute en una marca de tiempo específica con systemd

Programe el comando para que se ejecute en una marca de tiempo específica con systemd

Me gustaría programar la ejecución de un comando en un momento específico, identificado por una marca de tiempo de Unix. Parece que esto podría ser factible con systemd, usando systemd-run, pero ¿cómo funcionaría? ¿Y qué pasaría con el comando programado si la máquina se apaga o se suspende en el momento en que está programado el comando?

Pregunta relacionada: hacer lo mismo con atfrom atd(requiere analizar la marca de tiempo nuevamente en una fecha):¿Es posible utilizar el comando at para programar un trabajo para que se ejecute en una marca de tiempo determinada?

Respuesta1

systemd-runpuede programar un comando para que se ejecute en un momento específico,mientras:

  • el sistema no se apaga antes de ese momento, porque escribe un temporizador transitorio y un archivo de servicio en /run, que se borra al reiniciar, y
  • el sistema no se suspende durante ese tiempo específico, a menos que utilice la opción "WakeSystem" (ver más abajo).

Consulte aún más a continuación para conocer una opción de reinicio persistente.

Un ejemplo sencillo para systemd-run:

# generate an arbitrary timestamp, in seconds-since-the-epoch
timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "$(date -d @"$timestamp" +'%F %T')" \
  --timer-property=AccuracySec=1us \
  touch /tmp/done

Las partes importantes para llegar systemd-runa utilizar una marca de tiempo de segundos desde la época son:

  • para usar --on-calendary
  • aquí, usando la fecha GNU para convertir los segundos desde la marca de tiempo de la época a un formato que systemd-runentienda. Puede ingresar o convertir la marca de tiempo usted mismo, siempre que el resultado esté en un formatoformato que OnCalendar entiende.

La documentación actual de OnCalendar indica que admite directamente la entrada en una marca de tiempo de segundos desde la época. Ese soporte '@segundos' se agregó enversión del sistema 234(busque en esa página el archivo src/basic/calendarspec.c) encometer d80e5b7. Su versión de systemd puede ser anterior a este cambio; por ejemplo:

  • RHEL 7 comenzó con systemd 208 y luego se actualizó a la versión 219; RHEL 8 usa la versión 239 (árbitro).
  • Debian 8 usó la versión 215, Debian 9 usó la versión 232 y Debian 10 usa la versión 241 (árbitro).
  • Ubuntu 16.04 LTS tenía la versión 229, Ubuntu 17.10 tenía la versión 234 y Ubuntu 18.04 LTS tenía la versión 237 (árbitro).

Con una versión suficientemente nueva de systemd, puedes usar esta invocación:

timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "@${timestamp}" \
  --timer-property=AccuracySec=1us \
  touch /tmp/done

También he mostrado unpropiedad del temporizador de AccuracySec, que por defecto es 1 minuto y cuyo valor debes ajustar según la documentación:

Para optimizar el consumo de energía, asegúrese de establecer este valor lo más alto posible y tan bajo como sea necesario.

No lo he probado, pero también hay una opción de temporizador llamada WakeSystemque:

hacer que el sistema se reanude desde la suspensión, en caso de que se suspenda y si el sistema lo admite. Tenga en cuenta que esta opción solo asegurará que el sistema se reanude en los momentos adecuados, no se encargará de suspenderlo nuevamente una vez finalizado cualquier trabajo a realizar.

Lo integrarías en lo anterior así:

timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "$(date -d @"$timestamp" +'%F %T')" \
  --timer-property=AccuracySec=1us \
  --timer-property=WakeSystem=true \
  touch /tmp/done

Para pedirle a systemd que ejecute un comando en un momento determinado, de una manera quepersistir más allá de un reinicio, y que es independiente de cualquier sesión de inicio de sesión en particular, deberá colocar los archivos del temporizador y de la unidad de servicio en /etc/systemd/system/./etc/systemd/system es donde se almacena la configuración localpara sistema.

Un archivo de temporizador de muestra sería:

[Timer]
AccuracySec=1us
[Unit]
Description=2020-01-22 09:50:00 timer
[Timer]
OnCalendar=2020-01-22 09:50:00

y un archivo de servicio de muestra sería:

[Unit]
Description=my 2020-01-22 09:50:00 service
[Service]
ExecStart=
ExecStart=@/usr/bin/bash "/usr/bin/bash" "-c" "echo 2020-01-22 09:50:00 timer and service ran > /tmp/done"

Luego informaría a systemd sobre los archivos recargándolos:

systemctl daemon-reload

... y luego habilitando el temporizador:

systemctl enable foo.timer

... y luego iniciando el cronómetro:

systemctl start foo.timer

Es posible que desee eliminar periódicamente las unidades de servicio y temporizador caducadas de /etc/systemd/system, una vez que haya transcurrido su tiempo.

información relacionada