4

I've used cron for a while; I feel I understand some of its shortcomings, and how to work around them. One of these shortcomings is that cron is unaware of the status of other services during the boot process; i.e. it may cause issues for a job scheduled with the @reboot facility in cron when a service required in that job isn't available yet. I'll call this the cron @reboot issue.

One work-around to resolve this issue is to insert a sleep command before the @reboot script is started. For example, in the crontab entry:

@reboot sleep 15; /path/to/script.sh

AFAIK, this is common practice for dealing with the cron @reboot issue

It has been said that systemd can replace the @reboot facility, and offers users greater control during initialization/boot. The "cost" of this improvement is replacing a single line in crontab with a unit file and the systemd learning curve. But since the cron service itself is started under systemd (via /lib/systemd/system/cron.service on my Raspberry Pi buster OS), it seems that cron could be started in such a way that eliminated the cron @reboot issue. It seems a bit incongruous that under systemd one would need to continue using the sleep hack to address the cron @reboot issue.

I'm still working on my systemd merit badge, but have the notion that cron should be one of the last services initialized. I say this because if cron is the final service in the starting order, it then follows that all dependencies should also be satisfied, and the sleep hack in my @reboot jobs under cron can be eliminated.

While trying to learn how systemd could be instructed to start cron at or near the end of the initialization sequence, I found an answer stating cron.service can be started as the last & final process by inserting the Type=idle in /lib/systemd/system/cron.service. To test this using a before-and-after version of cron.service unit file seemed to be a reasonable approach; i.e.:

  1. run systemd-analyze plot > startup_order_noidle.svg
  2. add Type=idle to cron.service
  3. reboot
  4. run systemd-analyze plot > startup_order_idle.svg

Unfortunately, listing the startup order of services under systemd seems an inscrutable exercise. Using systemd-analyze iaw this post seemed to offer an answer, but it's not working as I had hoped - the cron.service is not always listed. Let me explain:

The .SVG file sizes are enormous, and I can't share them, but startup_order_noidle.svg did not show cron.service anywhere in the listing. OTOH, startup_order_idle.svg did show cron.service on the line following systemd-logind.service. IoW, without the Type=idle added, cron.service doesn't appear - even though it had been started.

To recap: Is there a reliable method under systemd to start cron after all other services/devices/targets/etc have been started? Is there a reliable method to verify this?

2
  • It seems that to avoid climbing the hillock that is using systemd timers for your scheduled tasks, you're going to climb the mountain that is screwing around with system services.
    – muru
    Commented Dec 8, 2021 at 1:04
  • @muru: Maybe... I don't know systemd well enough to comment on that. But I'm open to any answers that allow me to start cron after the system is "fully initialized".
    – Seamus
    Commented Dec 8, 2021 at 2:19

1 Answer 1

2

Generally with unit files you specify the "After=" and "Requires=" flags as you typically have a concrete "requirement" after which the service needs to be loaded.

In your case where you want this to be the absolute last service to load, I would suggest going with the approach of creating your own target, which will load after the currently configured last target (multi-user.target or graphical.target etc.).

In this scenario if new services are installed, they will typically default to a pre-configured target, such as multi-user, thus leaving your cron service as the absolute last one regardless of changes.

Coincidentally the question you linked contains a through description of how to do this: https://superuser.com/a/1543365

Regarding verifying startup order - you can use the command:

systemctl list-units [-all] [--state=xxx] *

With states:

  • inactive (optional)
  • activating
  • failed

As part of the pre-start exec in the cron service to print/log all the services that haven't started (or have failed), if the activating output is empty (or contains services which you know should start after cron) then you can be assured that cron was indeed the last to start.

Note that this is a workaround for systemd-analyze plot since you claim it was unreliable in your use case.

* Additional states are available: active, deactivating, dead, not-found. A brief explanation, with some additional sources, can be found here: https://superuser.com/a/896951

5
  • I'll take another look at the answer you linked. It seemed overly arcane compared to the one selected as the correct answer, but perhaps it actually works. But one part of the question isn't answered here is how to verify the starting order.
    – Seamus
    Commented Dec 9, 2021 at 3:38
  • @Seamus, I've updated my answer with a workaround for the systemd-analyze plot approach to verifying that cron indeed started last. Please note that if it didn't - this will not show the startup order of the not-yet-loaded services.
    – Alex
    Commented Dec 19, 2021 at 7:57
  • I'm confused by your last sentence re not showing the start order of not-yet-loaded services. That sounds like you will always get a false indication unless you got it right, and started cron last? It also sounds like - if you did get it right, there will also be no 'not-yet-loaded services'. Sorry for being thick, but this isn't quite clicking.
    – Seamus
    Commented Jan 4, 2022 at 23:31
  • @Seamus, Yep, reading it again I guess it is a bit unclear. What I meant was that with this method if cron does startup last - you will see no printout from the activating status. If however cron did not start last - you will see other services still in activating state. Note that inactive will output disabled services, so if you use that state flag you will need to do additional filtration based on your particular setup. As mentioned this will not indicate the order in which things startup, only the state of services in that particular point in time. Hope this clears things up a bit.
    – Alex
    Commented Jan 5, 2022 at 10:09
  • Note that the systemd default target after boot may not be always the same, run systemctl get-default to get the default target name for your system. Commented Sep 30, 2022 at 11:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .