How can I run cron every 1 second? there's only minutes option by default
Let cron start the job one time, the first time. Put the program in an infinite loop, sleep() for 1 second at the end of each loop. like this, in C:
int main( int argc, char ** argv ) {
while (1) {
// do the work
sleep(1000);
}
}
Could that work?
Cron executes stuff every minute. Use a script:
while :
do
sleep 1
some_command || break
done
or in one line:
while : ; do sleep 1 ; some_command || break ; done
This will wait 1 second in between each execution, so if your command takes .75 seconds to run, then this script will kick it off every 1.75 seconds.
You can't with cron, because 1 minute is THE minimum time interval available. You'd have to run a script that fires up 60 other scripts, with delays of 0 to 59 seconds, or a single script which re-runs itself 60 times.
But at that point, why not just run a single script outside of cron which does sleep(1) in a loop?
Related
I have this code that creates 20 parallel sqlplus instances, doing some queries and exits:
#!/bin/sh
for i in $(seq 1 20);
do
echo "CREATE TABLE table_$i (id NUMBER NOT NULL);
select * from table_$i;
! sleep 30
select * from table_$i;
! sleep 30
DROP TABLE table_$i;" | sqlplus system/password &
done
wait
I need to adjust this code if possible so it would run for an hour with the following conditions:
Always stay on 20 connections, if one sqlplus instance is closed (Finished it's process) another one should open, i need to maintain a certain amount of connections for X amount of time.
Is there anything i can add to this code that will achieve what i need?
For looping during an hour, see https://stackoverflow.com/a/22735757/3220113
runsql() {
i="$1"
end=$((SECONDS+3600))
SECONDS=0
while (( SECONDS < end )); do
# Do what you want.
echo "CREATE TABLE table_$i (id NUMBER NOT NULL);
select * from table_$i;
! sleep 30
select * from table_$i;
! sleep 30
DROP TABLE table_$i;" | sqlplus system/password
sleep 1 # precaution when sqlplus fails, maybe wrong password
done
}
for i in $(seq 1 20); do
runsql $i &
done
wait
Explanation:
The main loop at the bottom starts the function runsql 20 times in the background.
The function runsql could use $1 everywhere, I copy it to i for code that looks like the original.
SECONDS is a counter that is changed every second by the shell, so we do not need to call date.
3600 is an hour.
Inside (( .. )) you can do math without $ in front of variables.
My script should have n subroutines (my_proc) to run simultaneously, each of them runs bash script and one sub (check_procs) checks if subs has finished.
use strict;
use threads;
use threads::shared;
my %proc_status :shared;
my %thr;
foreach my $i (1,2,3,4) {
$proc_status{$i}=0;
}
sub my_proc {
my $arg=shift(#_);
while (1) {
sleep(2);
print "Proc $arg Started\n";
#exec("/bin/bash","sleep_for_10_sec.bash") or die("Can't exec"); # case 1
#`sleep_for_10_sec.bash &`; # case 2
print "Proc $arg Finished\n";
{
lock(%proc_status);
$proc_status{$arg}=1;
}
}
}
sub check_procs {
my $all_finished;
while (! $all_finished) {
sleep 5;
print "CHECK: \n";
$all_finished=1;
foreach my $num (1,2,3,4) {
if ($proc_status{$num} == 1) {
print "CHECK: procedure $num has finished\n";
} else {
$all_finished=0;
}
}
}
print "All jobs finished\n";
}
foreach my $num (1,2,3,4) {
$thr{"$num"} = new threads \&my_proc,$num;
}
my $thr_check= new threads \&check_procs;
$thr_check->join();
And here are the sleep_for_10_sec.bash
ls
# bunch of other stuff
sleep 10
echo "finished sleep"
I don't want my_proc subs to wait "sleep_for_10_sec.bash" command to be executed, after browsing I have found that either #case1 or #case2 should work, but they both fail.
the output of #case1:
Proc 1 Started
[ls result]
finsihed sleep
the output of #case2:
Proc 1 Started
Proc 2 Started
Proc 3 Started
Proc 4 Started
CHECK:
CHECK:
Proc 4 Finished
Proc 2 Finished
Proc 3 Finished
Proc 1 Finished
Proc 3 Started
Proc 1 Started
Proc 2 Started
Proc 4 Started
CHECK:
CHECK: procedure 1 has finished
CHECK: procedure 2 has finished
CHECK: procedure 3 has finished
CHECK: procedure 4 has finished
But I expect something like this :
Proc 1 Started
Proc 2 Started
Proc 3 Started
Proc 4 Started
Proc 1 Finished
Proc 1 Started
Proc 3 Finished
Proc 3 Started
Proc 4 Finished
Proc 4 Started
Proc 2 Finished
Proc 2 Started
CHECK:
CHECK:
CHECK:
CHECK: procedure 1 has finished
CHECK: procedure 2 has finished
CHECK: procedure 3 has finished
CHECK: procedure 4 has finished
Actually I get wanted result in case of redirecting output to " > log", but anyway after:
Proc 1 Started
Proc 2 Started
Proc 3 Started
Proc 4 Started
it waits "sleep_for_10_sec.bash" to finish.
This is my first project where I use "thread" and "exec", could someone help me on this ?
exec shouldn't be combined with threads. exec launches a new program within the current process, so when you call exec from one thread, the program the threads were executing disappears. Since the threads would have no program to execute, exec kills the threads as well.
It's not clear to me why case 2 doesn't work (edit: see ikegami's comment below). I would think it would launch the process, run it in the background, and allow the Perl thread to immediately continue. It doesn't seem to do that, but this code will:
system("/bin/bash sleep_for_10_sec.bash &"); # case 3
exec("/bin/bash","sleep_for_10_sec.bash") or die("Can't exec"); # case 1
exec replaces the program running in the current process with another program. At the same time, the existing threads are terminated (since the program they want to execute is no longer there), replaced with a single thread executing the new program.
This means that exec never returns (except on error). Threads or no threads, exec is not what you want, because you don't want your program to stop running.
But I expect something like this:
Are you sure you want to launch sleep_for_10_sec.bash 4 times every two seconds (meaning you can have up to 20 of them running at a time) as your desired output indicates?
Are you sure you don't care if sleep_for_10_sec.bash completes or not as your desired output indicates?
If so, why are you using threads at all? You could simply use the following:
sub start {
my $num = shift;
say "Proc $num Started";
system('bash -c sleep_for_10_sec.bash &');
say "Proc $num Finished";
}
for my $pass (1..2) {
start($_) for 1..4;
sleep 2;
start($_) for 1..4;
sleep 2;
start($_) for 1..4;
sleep 1;
if ($pass == 1) {
say "CHECK:";
} else {
say "CHECK: procedure $_ has finished" for 1..4;
}
}
I think you want
use threads;
use Thread::Queue qw( ); # 3.01+
use constant NUM_WORKERS => 4;
sub worker {
my $num = shift;
say "Job $num Started\n";
system("sleep_for_10_sec.bash"); # Make sure starts with #! and is executable.
say "Job $num Finished\n";
}
{
my $q = Thread::Queue->new();
for (1..NUM_WORKERS) {
while (defined( my $job = $q->dequeue() )) {
worker($job);
}
}
$q->enqueue(1..4, 1..4);
$q->end();
$_->join() for threads->list;
}
I found a interesting thing during creation of my crontab setting.
I used this command:
crontab -e
and fill this line:
*/55 * * * * export DISPLAY=:0 && /home/user/Documents/script.sh $2>/dev/null
My idea was create scheduler, which start script.sh every 55 minutes.
But this script is execute in this times (for example):
08:55, 09:00, 09:05, 09:55, 10:00, 10:05, ...
and I don't know why.
Can someone explain me that?
Replace the script like this and it should work.
*/5 * * * * [ $(( $(date +%s) / 60 % 55 )) -eq 0 ] && export DISPLAY=:0 && /home/user/Documents/script.sh $2>/dev/null
minute-hour-day-month-year
* any value
, value list separator
- range of values
/ step values
Another option is a self-replicating 'at' job. Only advantage over cron is that it is less obvious, and also if you needed it to kick off not every X minutes, but X minutes after the last job completed. So your script will just contain a line to create a new 'at' job before it exits. Something like:
echo "/full/path/to/my/script > /root/myScript.at.log" | at now + X minutes
so every 5 minutes it will do this:
number of seconds elapsed since 1. 1. 1970 will divided by 60 = how many minutes
echo $(date +%s)
1476201056 ... second
echo $(( $(date +%s) / 60 ))
24603351 ... minutes
after that it will use modulo on count of minutes
When result of modulo is 0, it will send TRUE value.
And it is a typical logical AND
[ $((......)) -eq 0 ] && export DISPLAY.. && .../script.sh
Thank you.
It is really helpful :)
Hey I got crontab that runs every 5 minutes and it looks like this
*/5 * * * * blablalba
How can I get it running every 5 minutes and 30 seconds?
Instead of using Cron, have your script re-start itself using this as the final line:
echo /path/to/script | at now + 330 seconds
Or to be more "precise" in the timing : take into accoutn how many seconds you spend running the script and take those out of the 330 seconds (5mn and 30s) :
#beginning of script
seconds_at_start=$(date +%s)
....
#end of script
seconds_at_end=$(date +%s)
nb_seconds=$((330 + seconds_at_start - seconds_at_end))
echo /path/to/script | at now + $nb_seconds seconds
Note: you may want to use bc for the calculation part to avoid running into strange behaviour in case your version of shell can't handle arithmetics on numerical as high as those returned by date +%s ...
If your version of at doesn't allow "now + XX second", then you can :
compute the number of seconds the script ran for
compute how many seconds to sleep ( sleep N ) to reach the next minute
and then : echo /path/to/script | at now + X minute
I am playing with using flock, a bash command for file locks to prevent two different instances of the code from running more than once.
I am using this testing code:
( ( flock -x 200 ; sleep 10 ; echo "original finished" ; ) 200>./test.lock ) &
( sleep 2 ; ( flock -x -w 2 200 ; echo "a finished" ) 200>./test.lock ) &
I am running 2 subshells (backgrounded). The (flock NUM; ...) NUM>FILE syntax is from flock's man page.
I expect that the first subshell will get an exclusive lock on test.lock, then wait 10 seconds, then print "original finished", all the time holding the lock. The second subshell will start at more or less the same time, wait 2 seconds, then try to get a lock on test.lock, but timeout after 2 seconds. If it gets a lock, then it'll print "a finished". If it doesn't get the lock, that subshell should stop, and nothing should be printed.
Since the first subshell is waiting longer, it will keep the lock for 10 seconds, so the second subshell should not get the lock, and shouldn't finish. i.e. one should see "original finished" printed and not both.
What actually happens is that "a finished" is printed, then "original finished" is printed.
This implies that that the second subshell is either (a) not using the same lock as the first subshell or (b) that it fails to get the lock, but continues to execute or (c) something else.
Why don't those locks work as I expect?
The issue is that, if the flock process fails to get the lock within the timeout, it has no way of killing the parent process (i.e. the shell that spawned it) - all it can do is return a failure return code. You need to check that return code before continuing:
flock <params> && <do other stuff>
so
( ( flock -x 200 ; sleep 10 ; echo "original finished" ; ) 200>./test.lock ) & ( sleep 2 ; ( flock -x -w 2 200 && echo "a finished" ) 200>./test.lock ) &
does what you want.