How to start service after the system time has been synchronized

Ensure that specific service is started after the system time has been synchronized.

I will use isc-dhcp-server service as an example to defer its startup time.

$ sudo systemctl status isc-dhcp-server
● isc-dhcp-server.service - LSB: DHCP server
   Loaded: loaded (/etc/init.d/isc-dhcp-server; generated)
   Active: active (running) since Tue 2019-09-17 22:36:05 GMT; 5min ago
     Docs: man:systemd-sysv-generator(8)
  Process: 19211 ExecStart=/etc/init.d/isc-dhcp-server start (code=exited, status=0/SUCCESS)
    Tasks: 2 (limit: 394)
   Memory: 8.9M
   CGroup: /system.slice/isc-dhcp-server.service
           ├─19013 /usr/sbin/dhcpd -4 -q -cf /etc/dhcp/dhcpd.conf
           └─19223 /usr/sbin/dhcpd -4 -q -cf /etc/dhcp/dhcpd.conf eth1

Sep 17 22:36:03 buster systemd[1]: Starting LSB: DHCP server...
Sep 17 22:36:03 buster isc-dhcp-server[19211]: Launching IPv4 server only.
Sep 17 22:36:03 buster dhcpd[19223]: Wrote 0 leases to leases file.
Sep 17 22:36:03 buster dhcpd[19223]: Server starting service.
Sep 17 22:36:05 buster isc-dhcp-server[19211]: Starting ISC DHCPv4 server: dhcpd.
Sep 17 22:36:05 buster systemd[1]: Started LSB: DHCP server.

Start system service after the system time has been synchronized

Ensure that system is configured to synchronize time.

$ timedatectl show-timesync
FallbackNTPServers=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
ServerName=0.debian.pool.ntp.org
ServerAddress=213.199.225.40
RootDistanceMaxUSec=5s
PollIntervalMinUSec=32s
PollIntervalMaxUSec=34min 8s
PollIntervalUSec=8min 32s
NTPMessage={ Leap=0, Version=4, Mode=4, Stratum=2, Precision=-21, RootDelay=1.113ms, RootDispersion=17.761ms, Reference=D4A06AE2, OriginateTimestamp=Tue 2019-09-17 22:39:26 GMT, ReceiveTimestamp=Tue 2019-09-17 22:39:26 GMT, TransmitTimestamp=Tue 2019-09-17 22:39:26 GMT, DestinationTimestamp=Tue 2019-09-17 22:39:26 GMT, Ignored=no PacketCount=10, Jitter=3d 21h 19.241389s }
Frequency=3871129

Ensure that systemd-time-wait-sync service is enabled.

$ 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; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:systemd-time-wait-sync.service(8)
$ sudo systemctl enable systemd-time-wait-sync
Created symlink /etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service → /lib/systemd/system/systemd-time-wait-sync.service.

Create drop-in configuration directory for isc-dhcp-server service.

$ sudo mkdir /etc/systemd/system/isc-dhcp-server.service.d

Ensure that it will start after reaching time-sync target.

$ cat <<EOF | sudo tee /etc/systemd/system/isc-dhcp-server.service.d/wait_for_time_sync.conf
[Unit]
After=time-sync.target
EOF

Reboot system

$ sudo reboot

Inspect systemd-time-wait-sync status.

$ 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 2019-09-17 22:52:20 GMT; 1min 0s ago
     Docs: man:systemd-time-wait-sync.service(8)
  Process: 212 ExecStart=/lib/systemd/systemd-time-wait-sync (code=exited, status=0/SUCCESS)
 Main PID: 212 (code=exited, status=0/SUCCESS)

Sep 17 22:51:51 buster systemd-time-wait-sync[212]: adjtime state 5 status 40 time Tue 2019-09-17 22:51:51.066820 UTC
Sep 17 22:52:20 buster systemd-time-wait-sync[212]: adjtime state 0 status 2000 time Tue 2019-09-17 22:52:20.448582 UTC
Sep 17 22:52:20 buster systemd[1]: Started Wait Until Kernel Time Synchronized.
Service systemd-time-wait-sync will wait infinitely till it can synchronize time. Services that depend on time-sync target will not start until this happens.

Service isc-dhcp-server will start after systemd-time-wait-sync exits.

$ sudo systemctl status isc-dhcp-server
● isc-dhcp-server.service - LSB: DHCP server
   Loaded: loaded (/etc/init.d/isc-dhcp-server; generated)
  Drop-In: /etc/systemd/system/isc-dhcp-server.service.d
           └─wait_for_time_sync.conf
   Active: active (running) since Tue 2019-09-17 22:52:20 GMT; 6s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 260 ExecStart=/etc/init.d/isc-dhcp-server start (code=exited, status=0/SUCCESS)
    Tasks: 1 (limit: 393)
   Memory: 6.7M
   CGroup: /system.slice/isc-dhcp-server.service
           └─264 /usr/sbin/dhcpd -4 -q -cf /etc/dhcp/dhcpd.conf eth1

Sep 17 22:52:20 buster systemd[1]: Starting LSB: DHCP server...
Sep 17 22:52:20 buster isc-dhcp-server[471]: Launching IPv4 server only.
Sep 17 22:52:20 buster dhcpd[483]: Wrote 0 leases to leases file.
Sep 17 22:52:20 buster dhcpd[483]: Server starting service.
Sep 17 22:52:22 buster isc-dhcp-server[471]: Starting ISC DHCPv4 server: dhcpd.
Sep 17 22:52:22 buster systemd[1]: Started LSB: DHCP server.

Inspect critical chain of units to confirm that it depends on time-sync target.

$ sudo systemd-analyze critical-chain isc-dhcp-server.service
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

isc-dhcp-server.service +2.077s
└─time-sync.target @30.998s
  └─systemd-time-wait-sync.service @127ms +30.870s
    └─systemd-journald.socket @122ms
      └─-.mount @121ms
        └─systemd-journald.socket @122ms
          └─...

Start service after the system time has been synchronized or timeout has been exceeded

Create drop-in configuration directory for systemd-time-wait-sync service.

$ sudo mkdir /etc/systemd/system/systemd-time-wait-sync.service.d/

Ensure that it will fail if it cannot synchronize time during specified period of time.

cat <<EOF | sudo tee /etc/systemd/system/systemd-time-wait-sync.service.d/timeout.conf                                                                                 
[Service]
TimeoutStartSec=5m
EOF

Disable time synchronization to perform this test.

$ sudo timedatectl set-ntp false

Reboot system

$ sudo reboot

Inspect systemd-time-wait-sync status.

$ 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)
  Drop-In: /etc/systemd/system/systemd-time-wait-sync.service.d
           └─timeout.conf
   Active: activating (start) since Tue 2019-09-17 22:58:38 GMT; 2min 29s ago
     Docs: man:systemd-time-wait-sync.service(8)
 Main PID: 211 (systemd-time-wa)
    Tasks: 1 (limit: 393)
   Memory: 1.0M
   CGroup: /system.slice/systemd-time-wait-sync.service
           └─211 /lib/systemd/systemd-time-wait-sync

Sep 17 22:58:38 buster systemd-time-wait-sync[211]: adjtime state 5 status 40 time Tue 2019-09-17 22:58:38.697335 UTC

It will fail after specified period of time as it cannot synchronize time.

$ 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)
  Drop-In: /etc/systemd/system/systemd-time-wait-sync.service.d
           └─timeout.conf
   Active: failed (Result: timeout) since Tue 2019-09-17 23:03:38 GMT; 291ms ago
     Docs: man:systemd-time-wait-sync.service(8)
  Process: 211 ExecStart=/lib/systemd/systemd-time-wait-sync (code=exited, status=0/SUCCESS)
 Main PID: 211 (code=exited, status=0/SUCCESS)

Sep 17 22:58:38 buster systemd-time-wait-sync[211]: adjtime state 5 status 40 time Tue 2019-09-17 22:58:38.697335 UTC
Sep 17 23:03:38 buster systemd[1]: systemd-time-wait-sync.service: Start operation timed out. Terminating.
Sep 17 23:03:38 buster systemd-time-wait-sync[211]: Exit without adjtimex synchronized.
Sep 17 23:03:38 buster systemd[1]: systemd-time-wait-sync.service: Failed with result 'timeout'.
Sep 17 23:03:38 buster systemd[1]: Failed to start Wait Until Kernel Time Synchronized.

isc-dhcp-server service will start after the timeout has been exceeded.

$ sudo systemctl status isc-dhcp-server● isc-dhcp-server.service - LSB: DHCP server
   Loaded: loaded (/etc/init.d/isc-dhcp-server; generated)
  Drop-In: /etc/systemd/system/isc-dhcp-server.service.d
           └─wait_for_time_sync.conf
   Active: active (running) since Tue 2019-09-17 23:03:40 GMT; 6s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 471 ExecStart=/etc/init.d/isc-dhcp-server start (code=exited, status=0/SUCCESS)
    Tasks: 1 (limit: 393)
   Memory: 6.7M
   CGroup: /system.slice/isc-dhcp-server.service
           └─483 /usr/sbin/dhcpd -4 -q -cf /etc/dhcp/dhcpd.conf eth1

Sep 17 23:03:38 buster systemd[1]: Starting LSB: DHCP server...
Sep 17 23:03:38 buster isc-dhcp-server[471]: Launching IPv4 server only.
Sep 17 23:03:38 buster dhcpd[483]: Wrote 0 leases to leases file.
Sep 17 23:03:38 buster dhcpd[483]: Server starting service.
Sep 17 23:03:40 buster isc-dhcp-server[471]: Starting ISC DHCPv4 server: dhcpd.
Sep 17 23:03:40 buster systemd[1]: Started LSB: DHCP server.

Enable time synchronization, so it can return to its normal state.

$ sudo timedatectl set-ntp true