Время в Raspberrypi - 3
“Да сколько уже можно про время в Raspberrypi?!” - скажут некоторые. Однако, несмотря на две предыдущие статьи, мне есть о чём написать. Опять.
Как я уже неоднократно писал, время можно получить двумя способами:
- подключившись к интернету
- используя RTC модуль
На некоторых станциях у меня стоит RTC модуль, на некоторых нет. Но я не особо переживал по этому поводу, так как станции имели постоянное подключение к интернету.
Запах приключений
Всё работало очень хорошо и стабильно, до тех пор пока я не обратил на странное поведения в логах.
Dec 24 03:20:07 raspberrypi java[447]: [1577147653365] observation time passed. skip 43466
Поначалу я не придал этому должного внимания, так как эта запись могла означать, что очередь на обработку сигналов переполнилась и последующее наблюдение пропустило своё окно. Не имеет смысл запускать задачу по наблюдению за спутником, если тот уже улетел.
Тем не менее несколько недель назад я заметил шаблон: сообщения появлялись только при старте приложения. Иногда одно, иногда несколько наблюдений отменялись. Однако, в этом не было ничего критичного. Все последующие наблюдения отрабатывали на ура.
Я решил выделить время и попытаться понять в чём же причина. И причина, конечно же, оказалось в системном времени. А именно в том, в какой момент системное время синхронизируется. Для простоты можно нарисовать простейшую диаграмму последовательности:
- стартует система
- запускается systemd-timesyncd и асинхронно запрашивает время
- запускается r2cloud и стартует наблюдения
- systemd-timesyncd получает асинхронный ответ и модифицирует системное время
Из такого описания явно следует проблема: все наблюдения рассчитаны на основе неправильного системного времени. А значит, когда оно изменится, должны быть отброшены.
Решение близко
К счастью, решение есть! Оно называется systemd-time-wait-sync.service
. Этот сервис был добавлен сравнительно недавно в Debian Buster дистрибутив. Он, как следует из названия, дожидается, когда будет получен асинхронный ответ по протоколу NTP, и отправляет специальное событие time-sync.target
.
Для того чтобы всё заработало, нужно сделать несколько шагов. Во-первых, нужно включить сервис:
sudo systemctl enable systemd-time-wait-sync
Можно проверить статус сервиса:
sudo systemctl status systemd-time-wait-sync
● systemd-time-wait-sync.service - Wait Until Kernel Time Synchronized
Loaded: loaded (/lib/systemd/system/systemd-time-wait-sync.service; enabled; vendor preset: enabled)
Active: active (exited) since Tue 2020-08-18 12:01:07 BST; 1 day 8h ago
Docs: man:systemd-time-wait-sync.service(8)
Process: 111 ExecStart=/lib/systemd/systemd-time-wait-sync (code=exited, status=0/SUCCESS)
Main PID: 111 (code=exited, status=0/SUCCESS)
Aug 18 11:17:01 raspberrypi systemd-time-wait-sync[111]: adjtime state 5 status 40 time Tue 2020-08-18 10:17:01.037765 UTC
Во-вторых, необходимо, чтобы наш сервис, в данном случае r2cloud, стартовал только тогда, когда время синхронизировано. Для этого нужно в описание юнита добавить зависимость:
[Unit]
Description=R2Cloud Service
After=time-sync.target
Результат
В результате r2cloud теперь стартует после того, как время синхронизировано:
Aug 18 12:01:07 raspberrypi systemd[1]: Started Wait Until Kernel Time Synchronized.
Aug 18 12:01:07 raspberrypi systemd[1]: Reached target System Time Synchronized.
Aug 18 12:01:07 raspberrypi systemd[1]: Started R2Cloud Service.
Все наблюдения запускаются в своё время и r2cloud станции по всему миру стали чуть эффективнее работать. Ура!