8

I'm using systemd-timer to periodically run a script which consumes a webservice.
Problem is, upon system resume or wake-up, internet connectivity would not get started right away but the timer gets fired and hence the script returns error (If the service waits for a couple of seconds, the script would run correctly and there would be no need to postpone the task until next run.)

1- How can I make it so that the timer (or the service associated with it), waits until net connectivity is available?

2- How can I make the timer (or service) not call the script when system is not online yet?

  • How about just adding something like sleep 5 at the top of your script? Might not be a solution, but with appropriate choice of sleep time should do as a workaround. – Peregrino69 Sep 16 '21 at 09:29
  • 2
    https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ – Henri Menke Sep 16 '21 at 09:36

1 Answers1

14

Add After=network-online.target to the [Unit] section of the timer.

Explanation:

Timers do accept all the relative ordering commands in the [Unit] section that are known for services. In fact both the [Unit] and [Install] sections are identical for timers and services. Form the official manuals:

A unit configuration file whose name ends in ".timer" encodes information about a timer controlled and supervised by systemd, for timer-based activation.

This man page lists the configuration options specific to this unit type. See systemd.unit(5) for the common options of all unit configuration files. The common configuration items are configured in the generic [Unit] and [Install] sections. The timer specific configuration options are configured in the [Timer] section.

That said you need to know about network-online.target that defines if a network is up.

network-online.target is a target that actively waits until the nework is "up", where the definition of "up" is defined by the network management software. Usually it indicates a configured, routable IP address of some kind. Its primary purpose is to actively delay activation of services until the network is set up.

Limitations

network-online.target is not checking for internet but for network connections. The LAN of course might not have internet access per se. If you cannot rely on the router or your ISP to provide a connection, you would have to make e.g. a special test-internet.service that pings some website and only is defined active after it succeeded once (and otherwise restarts on failure every 15s or so). That should be a Type=oneshot and RemainAfterExit=yes kind of service. But I assume that this is not what you asked for.

Scopes: system/user

Be careful, as network-online.target is a system scope unit. Units in the user scope will not see it and fail to start. This can be fixed by creating a linked unit: systemctl --user link /lib/systemd/system/network-online.target. The path can vary, the location can be checked by running: systemctl show --property FragmentPath network-online.target

FelixJN
  • 13,566
  • Thanks, do I also need to add Wants=network-online.target? – Zeta.Investigator Sep 16 '21 at 11:17
  • 2
    Wants will also make the timer try to start the network target. You may add it, but I think for your case it is not that necessary - since I assume you always start the network by default. If your connection is unstable, you may rather think of something like BindsTo=, i.e. stopping the timer if the network connection breaks. More details on the relative dependency options here: Service unit configuration – FelixJN Sep 16 '21 at 11:27
  • and what would be the difference if I add After=network-online.target to the Unit section of corresponding .service file (not .timer)? – Zeta.Investigator Sep 16 '21 at 11:29
  • Simple: If you do not define to start the timer after online target, the countdown will start earlier (e.g. when you defined it as WantedBy=multi-user.target in the [Install] section it will start at boot time - independently of the network status). If you define it in the service file, it will wait for the online target after triggering the service via the timer. – FelixJN Sep 16 '21 at 11:37
  • BindsTo= option is only relevant in boot process? I mean, can I use it to disable the timer when network suddenly turns off and re-enable it when it becomes available? (After boot). I used BindsTo= and After= with network-online.target but when network came back online, the timer didn't reactivate – Zeta.Investigator Sep 16 '21 at 15:20
  • @Zeta.Investigator That is an emergeny stop only. Check the PartOf= directive for a start-and-stop dependency. More details here – FelixJN Sep 16 '21 at 15:53
  • 1
    Sorry for bothering again...actually my timer/service are defined in .config/systemd/user (user-level)...so I can't depend on network-online.target which is a system service, right?

    I need to write my own connection-detector service at user-level right?

    – Zeta.Investigator Sep 17 '21 at 14:57
  • 1
    No worries. - Yes, system level and user level are fully independent - see here or here. I'd suggest you make a small ping test service to some reliable internet address. – FelixJN Sep 19 '21 at 10:52