Allowing user to configure cron - python

I have this bash script on the server that runs every hour, via cron. I was perfectly happy, but now the user wants to be able to configure the frequency through the web interface.
I don't feel comfortable manipulating the cron configuration programmatically, but I'm not sure if the other options are any better.
The way I see it, I can either:
Schedule a script to run once a minute and check if it should really run "now"
Forgo cron altogether and use a deamon that is its own scheduler. This probably means rewriting the script in python
...or suck it up and manipulate the cron configuration from the web interface (written in python BTW)
What should I do?
EDIT: to clarify, the main reason I'm apprehensive about manipulating cron is because it's basically text manipulation with no validation, and if I mess it up, none of my other cron jobs will run.
Here's what I ended up doing:
Taking stefanw's advice, I added the following line at the top of my bash script:
if [ ! `cat /home/username/settings/run.freq` = $1 ]; then
exit 0
fi
I set up the following cron jobs:
0 */2 * * * /home/username/scripts/publish.sh 2_hours
#hourly /home/username/scripts/publish.sh 1_hour
*/30 * * * * /home/username/scripts/publish.sh 30_minutes
*/10 * * * * /home/username/scripts/publish.sh 10_minutes
From the web interface, I let the user choose between those four options, and based on what the user chose, I write the string 2_hours/1_hour/30_minutes/10_minutes into the file at /home/username/settings/run.freq.
I don't love it, but it seems like the best alternative.

Give your users some reasonable choices like every minute, every 5 minutes, every half an hour, ... and translate these values to a cron job string. This is user friendly and forbids users to tamper directly with the cron job string.

You could use a python scheduler library that does most of the work already:
pycron
scheduler-py

What about Webmin? I have never used it myself but it seems you could configure the cron module and give permissions to the user who wants to configure the job.

Well something I use is a main script started every minute by cron. this script check touched files. If the files are there the main cron script start a function/subscript. You just have to touch a defined file and "rm -f"ed it when done. It has the side benefits to be more concurrent proof if you want other way to start jobs. Then you can use your favourite web programming language to handle your users scheduling ...
The main script looks like :
[...]
if [ -e "${tag_archive_log_files}" ]; then
archive_log_files ${params}
rm -f ${tag_archive_files}
fi
if [ -e "${tag_purge_log_files}" ]; then
purge_log_files ${params}
rm -f ${tag_purge_log_files}
fi
[...]

I found a module that can manipulate the cron info for me. It's called python-crontab, and it's available with easy_install. From the source:
Example Use:
from crontab import CronTab
tab = CronTab()
cron = tab.new(command='/usr/bin/echo')
cron.minute().during(5,50).every(5)
cron.hour().every(4)
cron2 = tab.new(command='/foo/bar',comment='SomeID')
cron2.every_reboot()
list = tab.find('bar')
cron3 = list[0]
cron3.clear()
cron3.minute().every(1)
print unicode(tab.render())
for cron4 in tab.find('echo'):
print cron4
for cron5 in tab:
print cron5
tab.remove_all('echo')
t.write()
(I kept googling for "cron" and couldn't find anything. The keyword I was missing was "crontab").
I'm now deciding if I'll use this or just replace cron entirely with a python based scheduler.

Related

using WDT to monitor if my python program crashes

Background
I'm struggling to find a example of WDT in the way I want to use it. Wondering if I misunderstanding its use.
my python writing is pure hobby, honestly Classes intimidate me.
in short my program reads a number of sensors connected to a raspberry pi and writes the data to a cloud hosted object database.
i have an intermittent error that while I try to figure out I want to implement a based watchdog timer.
This is what I'd like to implement so in the very least I continue to collect and store data.
I've read about the builtin watchdog timer the raspberry pi has built in here: https://diode.io/raspberry%20pi/running-forever-with-the-raspberry-pi-hardware-watchdog-20202/
The problem I want the raspberry pi to reboot if my program hangs, but when that happens the OS is still fine, so the solution in the link above is not effective.
What I'd like to implement:
set the builtin watchdog timer to reboot the raspberry pi after 200 seconds without restarting (patting?) the timer. I think the instructions for this are in the link above.
Within my python script, after I iterate through each sensor, restart (or pat?) the watchdog timer and if 200 seconds elapse between pattings (meaning my program hangs) then RPi reboots.
is this possible?
can someone help me with some simple code? I was hoping to keep this simple and avoid classes and/or threads...
thank you in advance
The WDT is probably not the right solution for the problem you are describing. Based on your description, it sounds like what you have is a program that is intended to run periodically (either on a fixed schedule or in response to some event), and that program currently has a bug that is causing it to hang intermittently and never complete it's task or terminate.
The first and best way to solve that, I'm sure you can guess, is to fix the bug. But your thinking is not unreasonable either, and doing what you describe is very common. There are many valid approaches that will do what you want without the complexity of trying to deal with a hardware timer. One of the easiest is probably to just wrap the program in a shell script and use the timeout command to limit how long it is allowed to execute before it is terminated.
Assuming the script is located at /home/user/my_script.py, and you want to run it every 10 minutes, allowing it 2 minutes before it is killed, this would work:
create a wrapper shell script:
#!/usr/bin/env bash
if ! timeout 120s python /home/user/my_script.py; then
msg="$(date) - script exceeded timeout and was killed"
else
msg="$(date) - script ran successfully"
fi
echo "${msg}" >> /home/user/my_script.log
put the script in a file, say at /home/user/wrapper_script.sh and run chmod 755 /home/user/wrapper_script.sh to make it executable.
schedule the script to run every 10 minutes using cron. At a shell, use crontab -e to edit the users crontab file and add a new line like this:
*/10 * * * * /home/user/wrapper_script.sh
now, every 10 minutes the wrapper will start automatically, and it will kick off the python script. It will wait 2 minutes for the script to stop normally, after which it will reach the timeout and terminate it.
Note: depending on how your python program is written, you might have to use some other options to the timeout command to specify which signal it should use to stop the program. If it is a very basic python script, it should be fine using the default.
Edit: based on the comments, you might be able to just change the command you're using to this:
xterm -T "HMS" -geometry 100x70+10+35 -hold -e sudo timeout 120s /usr/bin/python3 /home/pi/h$
Doing that won't actually schedule the script to run at any fixed interval, so it assumes you already have something in place to handle that. All this will do is make srue that the script is restricted to 120 seconds of run time before it is killed.

How to run a shell script once a day?

I am trying to run this particular shell script only one time, daily. Here's my code for runLucene.py:
#!/usr/bin/env python
import os
from extras.download_datos_desambiguar import news_Lucene
x=datetime.today()
y=x.replace(day=x.day, hour=09, minute=00, second=0, microsecond=0)
delta_t=y-x
secs=delta_t.seconds+1
def fourdlife():
print "checking function"
os.system("~/code/4dlife_repo/4dbatch/src/engines/extras/download_datos_desambiguar/news_Lucene.py")
t = Timer(secs, fourdlife)
t.start()
print "timer started"
I am running this code in my ProcesosContinuous.py file like this:
while True:
os.system("./runl.sh")
#some other processes
where runl.sh is
python ~/code/4dlife_repo/4dbatch/src/engines/extras/download_datos_desambiguar/news_Lucene.py
This python code is always running on my apache2 server.
However, this is working at any given hour and not just the specified hour. What am I doing wrong?
Also, I feel there is a much better way to do this. I looked at the cron task but that's not what I am looking for. I don't want my program to go to sleep() because I need the other processes to run after the runl.sh process. What is the best way to do this?
The command crontab -e will open up an interactive editor within which you can define a cron job.
Within that editor's buffer, you can then enter a line such as the following (and then save it):
00 00 * * * /path/to/script.sh
This command will run script.sh every midnight.
cron is always doing its thing, I think it's quite a bit better to use that rather than having a python script dedicated to constantly checking if it's time to run the shell script.
With that said, when you create the crontab, it'll go under the users crontab, so just watch the user and/or -u it.

Restart Python with threading or crontab

I have written a function that crawls and clusters news articles. I want this function to restart every 10 minutes, aiming to get the newest articles. I wrote a Python script that this with the help of threading module:
import threading
def run():
do_it()
if not END:
threading.Timer(600.0, run).start()
END = False
threading.Timer(600.0, do_it).start()
It works fine with Python IDLE. Now I see in different forums that "crontab" is mentioned for this purpose. Since I plan to host this application on the web and since I have no prior experience with web development/hosting, what would you suggest to me: to continue with the previous code or to try to do it with the "crontab" function? I am working with the Django framework.
Using Django doesn't really work in this context. if you want to use a cron script then you will want it running independently of your webserver (you don't want your webserver ending after you finish the script). Alternatively you could start up a GET or POST request to an already running Django instance by this method.
First type crontab -e at a prompt in your unix based os or mac. (since you mentioned crontab I'll assume your not using windows)
This will allow you to edit a file for the user you are logged in as. This is the line you will want to type to get a do_it.py file to run every ten min.
*/10 * * * * do_it.py
For more information at your prompt type man 5 crontab. Other modifications you could make are prefixing the word sudo to the command which would allow you to change root's crontab.

How to schedule an action in python?

I'd like to know how to preform an action every hour in python. My Raspberry Pi should send me information about the temp and so on every hour. Is this possible?
I am new to python and linux, so a detailed explanation would be nice.
write a python code for having those readings from sensors in to text or csv files and send them to you or to dropbox account
and then put a cron job in linux to run that python script every hour
type in your command line
sudo su
then type
crontab -e
In opened file enter:
/ 0 * * * * /home/pi/yourscript.py
where /home/pi/yourscript.py is your fullpath to python script and it will execute this "yourscript.py" every 60 min.
To send your code to you - you have to choose some way-
1) you can send it to your inbox
2) to dropbox account
3) to sql data base
In any case you have to write script for that.
you can check out the sched module (in the Python standard library).
personally, I'd keep it simpler, and just run your script every hour using a system scheduler like cron.
a basic crontab entry to run hourly (on the hour) might look like this:
0 * * * * /home/foo/myscript.py > /dev/null 2>&1
if you really want to write a scheduler in Python, see some of the answers given here: How do I get a Cron like scheduler in Python?
The easiest way would be to set up a cron job to call a python script every hour.

How do I know if jobs have been/are performing? - Crontab

I have followed the suggestion in this question
as I am using Django, I have set the script to store date and time of each run of the script in the db, but no entry has been stored yet in the database.
Is there a way to figure out, other than typing "top" and searching through?
First, I would probably configure cron to mail yourself any output by using MAILTO:
In /etc/crontab:
MAILTO=username
Second, I usually add something to my script that (almost) cannot possibly fail, like the following:
#!/bin/sh
echo "$0 ran on `date +%c`" >> /tmp/crontab_test.log
# ... rest of program
If you're calling a python script directly from cron, you could do something similar or create a wrapper shell script.
If you have sendmail installed, you can add the following to '/etc/aliases'
root: your_name#domain.com
After you do that, update the aliases running this command:
sudo newaliases
Cron will automatically email you every time a job is run. No need to specify that in the crontab file.
Also, make sure you test your email capabilities (e.g. make sure you are able to send emails from the server) and lastly, create a trivial cronjob and test if you receive an email.
Do not assume!
In addition to setting up cron to send email, you can send the output of cron to a seperate syslog log facility by adding the following to your /etc/syslog.conf.
# Log cron stuff
cron.* /var/log/cron.log
This should log a message to /var/log/cron.log each time a job is run.

Categories

Resources