6

When I shutdown and power off the Raspberry Pi 3b and then power it up again the next day, I get wrong starting date/time printed when checking sudo systemctl status DustSensor. The printed date/time is from the date/time of the shutdown.

How can I delay the startup of services until the date/time is corrected from the NTP?

At shutdown and power off:

Feb 23 21:09:24 rp3b systemd[1]: Stopping DustSensor.service...

At startup (power on) the next day, still approx. the old date/time:

Feb 23 21:09:35 rp3b systemd[1]: Started DustSensor.service.

A bit later the date/time is corrected, but sudo systemctl status DustSensor gives the old date/time (not shown here):

Feb 23 21:09:51 rp3b systemd[826]: Started D-Bus User Message Bus.
Feb 24 09:17:48 rp3b systemd[1]: Time has been changed
Feb 24 09:17:48 rp3b systemd-timesyncd[277]: Synchronized to time server [2a01:4f8:c17:b8f::2]:123 (2.debian.pool.ntp.org).
Feb 24 09:17:48 rp3b systemd[1]: apt-daily.timer: Adding 1h 24min 33.643221s random time.
Feb 24 09:17:48 rp3b systemd[1]: apt-daily-upgrade.timer: Adding 22min 10.691517s random time.
Feb 24 09:17:48 rp3b systemd[826]: Time has been changed
Feb 24 09:17:48 rp3b systemd[1]: Reached target Network is Online.

Here's my DustSensor.service file:

[Service]
ExecStart=/home/pi/SDS011_Feinstaub_Sensor.py
WorkingDirectory=/home/pi
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=DustSensor
User=pi
Group=pi

[Install]
WantedBy=multi-user.target

With the suggestion and the example hello.service:

[Unit]
Description=Hello After Time Sync
After=time-sync.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/echo "$(date) Hello world, just started"

[Install]
WantedBy=multi-user.target

I get this where only after starting the hello.service the date/time is updated

journalctl -b | egrep '(ello|anged|ync)'
Feb 28 10:48:54 rp3b systemd[1]: Starting Network Time Synchronization...
Feb 28 10:48:55 rp3b systemd[1]: Started Network Time Synchronization.
Feb 28 10:48:55 rp3b systemd[1]: Reached target System Time Synchronized.
Feb 28 10:49:00 rp3b systemd[1]: Starting Hello After Time Sync...
Feb 28 10:49:00 rp3b systemd[1]: Started Hello After Time Sync.
Feb 28 10:49:11 rp3b bluetoothd[570]: Failed to obtain handles for "Service Changed" characteristic
Feb 28 11:35:51 rp3b systemd[1]: Time has been changed
Feb 28 11:35:51 rp3b systemd[499]: Time has been changed
Feb 28 11:35:51 rp3b systemd-timesyncd[271]: Synchronized to time server [2a02:2028:ff01:14::13]:123 (2.debian.pool.ntp.org).

Also this shows the wrong starting time:

sudo systemctl status hello
\u25cf hello.service - Hello After Time Sync
   Loaded: loaded (/etc/systemd/system/hello.service; enabled; vendor preset: enabled)
   Active: active (exited) since Thu 2019-02-28 10:49:00 CET; 1h 16min ago
  Process: 355 ExecStart=/bin/echo $(date) Hello world, just started (code=exited, status=0/SUCCESS)
 Main PID: 355 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/hello.service

Feb 28 10:49:00 rp3b systemd[1]: Starting Hello After Time Sync...
Feb 28 10:49:00 rp3b systemd[1]: Started Hello After Time Sync.

6

To syncronize with the time service there is a special time-sync.target. In man systemd.special you will find:

time-sync.target
Services responsible for synchronizing the system clock from a remote source (such as NTP client implementations) should pull in this target and order themselves before it. All services where correct time is essential should be ordered after this unit, but not pull it in. systemd automatically adds dependencies of type After= for this target unit to all SysV init script service units with an LSB header referring to the "$time" facility.

But this does not help much because this is only for initializing the time-sync service. After intitializing it needs some time to connect to the time server and get the clock synchronized to it. The systemd-timesyncd.service notifies it to the systemd manager so you will find something like this in the journal:

systemd-timesyncd[403]: Synchronized to time server 144.76.60.190:123 (2.debian.pool.ntp.org).

I have looked for systemd-notify if we can start an unit depending on this notify but haven't found anything. So I will look into the journal if I find the notify. If not then the Unit will fail to start but after a time it will restart and try again. Modify your Unit so it looks like this:

[Unit]
Description=SDS011 Feinstaub Sensor
After=time-sync.target

[Service]
Restart=on-failure
RestartSec=30
ExecStartPre=/bin/bash -c '/bin/journalctl -b -u systemd-timesyncd | /bin/grep -q "systemd-timesyncd.* Synchronized to time server"'
ExecStart=/home/pi/SDS011_Feinstaub_Sensor.py
WorkingDirectory=/home/pi
SyslogIdentifier=DustSensor
User=pi
Group=pi

[Install]
WantedBy=multi-user.target

You do not need StandardOutput=syslog and StandardError=syslog. That's default.

  • Unfortunately, this didn't help: Feb 27 09:05:01 rp3b systemd[1]: Started DustSensor. still comes before Feb 27 09:46:11 rp3b systemd[1]: Time has been changed resulting in pretending the service started 45 mins ago whereas the system was booted 5 mins ago. – monok Feb 27 at 9:02
  • @monok On the research why your service fails to start after time sync I have found that there is a special target. So using systemd-timesyncd.service was not the right dependency. I have updated the answer. – Ingo Feb 27 at 11:28
  • This time it does not start. I see Feb 27 14:01:24 rp3b systemd-timesyncd[277]: Synchronized to time server [2a02:c205:2009:8290::1]:123 (2.debian.pool.ntp.org). . Does it has to to with missing target.wants? I see when I execute ls timers.target.wants apt-daily.timer apt-daily-upgrade.timer – monok Feb 27 at 13:14
  • @monok No, the docu says: "All services where correct time is essential should be ordered after this unit, but not pull it in." "Pull in" means Wants= and that should not be used for services starting after time sync. And as you see the time sync service is started and don't need Wants=. What can you see with systemctl status DustSensor.service why it does not start? I have updated the answer with the test unit I have used to verify. – Ingo Feb 27 at 14:00
  • in my previous post I was not correct saying the service wasn't started. It was started but the reported date/time was wrong and I didn't see an output. Using your hello example I see this after reboot from sudo systemctl status hello: Active: active (exited) since Thu 2019-02-28 10:49:00 CET; 53min ago...Feb 28 10:49:00 rp3b systemd[1]: Starting Hello After Time Sync... Feb 28 10:49:00 rp3b systemd[1]: Started Hello After Time Sync.. – monok Feb 28 at 10:47
4

The actual feature was added to systemd in https://github.com/systemd/systemd/pull/8494 which is included in version 239

See docs in [1]:

systemd-time-wait-sync is a system service that delays the start of units that depend on time-sync.target until the system time has been synchronized with an accurate time source by systemd-timesyncd.service.

This means that you need to both enable systemd-time-wait-sync and Wants=time-sync.target

[1] https://www.freedesktop.org/software/systemd/man/systemd-time-wait-sync.service.html

  • 1
    Thanks, good to know. We will use it with next Raspbian Buster. Raspbian Stretch now is still using systemd 232 :-( – Ingo Mar 11 at 0:47
1

If you are willing to install ntpstat on your pi then you can accomplish this in another way.

The steps you then need to follow are:

  • install ntpstat
  • Create a shell script that calls ntpstat every second and only exits when it has a exit code of 0 (indicating that the time on the device has connected to a time server and syncronized the time
  • Create a oneshot systemd service that executes the above shell script
  • Modify your time synced dependent service to run only after the ntpstat service has run

Install ntpstat

sudo apt-get install ntpstat

Create the shell script that queries ntpstat

/usr/local/bin/check_time_synced.sh

#!/bin/bash

ntpstat
while
     printf "Time not synced yet\n"
     sleep 1s
     ntpstat
     (( $? ))
do
    :
done

printf "Successfully synchronized the time.\n"

Create the systemd oneshot service that calls the above script

/etc/systemd/system/ntpsync.service

[Unit]
Description=Checks the status of the ntp daemon. Only return when the time has been successfully synced
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/check_time_synced.sh
Type=oneshot

[Install]
WantedBy=multi-user.target

And enable the service

sudo systemctl enable ntpsync.service

Modify your own date time dependant service to start only after the ntpsync.service

[Unit]
Description=Hello After Time Sync
After=ntpsync.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/echo "$(date) Hello world, just started"

[Install]
WantedBy=multi-user.target

After this, reboot the pi and your service should only start when the unit has the correct time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.