I am running a script using crontab at reboot but somehow the part of the code where some file is being sent to a S3 bucket in AWS, doesn't work. I have included an initial wifi check in the same script and shows not connected to any network (in the cronjob log file), although on the Raspi's head I can see it is connected to the network. Infact the code works great if it is run from the code editor without any issues. I am wondering how to fix it.
Basically you can't. There are literally thousands of similar Questions on this site.
Current Linux (since 2015) uses
systemd which runs processes asynchronously at boot - so you can no longer guarantee that anything is running when your script is executed. (My Pi3B+ shows network-online.target @1min 31.799s)
The only reliable solution is to write a systemd script that includes
After=network.target. This unfortunately is more complex.
Some use a brute force approach and include a delay in cron scripts.
There used to be some useful guides on https://www.raspberrypi.com/ but unfortunately general Linux guides seem to have been removed so you should look at or search on https://unix.stackexchange.com/questions
There is an option in
raspi-config to wait for network on boot which may work, but I haven't used and am unsure how this interacts with cron.
One Answer which may help is https://raspberrypi.stackexchange.com/a/121944/8697
The cause of your issue is due to the fact that
cron does not have situation awareness.
cron is doing the job it was designed to do, but its job does not include being aware of whether or not the network services your job needs is available.
Since you posted this question, I'll guess this is a surprise to you. It was also a surprise to me when I learned it many years ago. Today however, the situation is different; rather odd and needlessly complicated - to my way of thinking. Nevertheless, there is a solution to your issue that is not complicated: You may simply ask
sleep for a while until your network is available. This is simply done by structuring your
@reboot job in
crontab as follows:
@reboot /usr/bin/sleep 60; <your current crontab entry>
This command will delay the start of your
cron job for 60 seconds. There is nothing magic about 60 seconds; it may be 10 seconds, or it may be 180 seconds - this will depend on how quickly your network services become available to your RPi. Play around with values until you find one that works reliably for your situation.
This is not an efficient solution - it is a simple solution. There are many alternatives to this solution; in fact your question indicates you may have implemented one in the code for your job/script by performing a
wifi check. This solution will work perfectly well if you put that test in a loop (perhaps with a
sleep command) that defers proceeding until the network services are available.
FWIW, in an effort to provide some additional context, my view of the bigger picture follows:
Why is this necessary, and what are other alternatives?
cron has been around for quite a long time. It was designed to schedule jobs; i.e. to cause them to be started at a specified time. It was never a
cron requirement to analyze the jobs it scheduled to learn what resources they required - that was the responsibility of the user who programmed the job - as you have begun to do in your
In Unix & Linux, starting services has always been the responsibility of
init. In most modern Linux systems - since 2015 - the role of
init has been filled by a program called
systemd. In other words
systemd controls the sequence in which services are started during the boot process, and
systemd is responsible for knowing the point in time (or sequence) at which network services become available.
crond itself is started by
systemd during the boot process. Consequently, since
systemd - as the
init system for Linux - is responsible for sequencing the start of all services (including
crond and networking services), it is reasonable to expect that
crond would not be started until network services were available. Unfortunately, the cognoscenti behind
systemd have not done this. No one seems to know why, but the question has been asked frequently with few clear or concise answers.
To be sure, it is possible for users/admins to modify the unit file for
crond to cause it to start later in the boot process - after network services become available. However, you'll first need to invest the time necessary to learn the vocabulary, syntax and design of
systemd to make that change. It's not simple, but it can be done if you feel the benefits justify the investment of your time.
I have included an initial wifi check in the same script and shows not connected to any network
Sounds like you just want your script to do the wifi check in a loop waiting for the network to come up. Something like:
echo Waiting for wifi... while ! wifi_check; do sleep 1 done echo Got wifi, continuing