30秒ごとにcronを実行する


313

30秒ごとに実行する必要があるcronがあります。

これが私が持っているものです:

*/30 * * * * /bin/bash -l -c 'cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'''

実行されますが、これは30分または30秒ごとに実行されますか?

また、私はそれを頻繁に実行する場合、cronが使用に最適なツールではない可能性があることを読んでいます。Ubuntu 11.04で使用またはインストールできる別の優れたツールはありますか?上記のcronを修正する方法はありますか?


CommaToast、そしてあなたのJavascriptまたはJavaアプリが何らかの理由でフォールオーバーして終了するとどうなりますか?どのように再起動しますか?:-)
paxdiablo 2015

12
NodeJSアプリを少し追加します(笑)。なぜ小さなC ++アプリではないのですか?ここでは、「cron」という名前を付けて、サービスとして実行できます。
Andrew


ユーザープロファイルを確認しているときにこれを見つけたところ、1時間以内にオンラインであることがわかりました(accがまだ使用されているかどうかを確認するためだけです)、以下の回答のいずれかを受け入れなかった具体的な理由はありますか?
Fabian N.

回答:


731

あなたは指定子を持っ*/30ています-それは毎分を意味しますが、30のステップで(つまり、30分ごとに)。以来、サブ分の解像度にダウンしていない、あなたは別の方法を見つける必要があります。cron

1つの可能性は、少々簡単ではありませんが(a)、2つのジョブを1つ30秒オフセットすることです。

# Need these to run on 30-sec boundaries, keep commands in sync.
* * * * *              /path/to/executable param1 param2
* * * * * ( sleep 30 ; /path/to/executable param1 param2 )

コメントを追加してフォーマットし、同期を維持しやすいようにしています。

両方のcronジョブは実際には毎分実行されますが、後者はジョブの「肉」を実行する前に30分間待機し/path/to/executableます。

他の(非cronベースの)オプションについては、ここで他の回答、特にfcronとに言及しているものを参照してくださいsystemd。これらは、システムにそれらを使用する能力があることを前提としておそらく望ましいでしょう(インストールfcronやディストリビューションのインストールなどsystemd)。


kludgyソリューションを使用したくない場合は、小さな変更を加えたループベースのソリューションを使用できます。プロセスを何らかの形で実行し続けることを管理する必要がありますが、それがソートされると、次のスクリプトが機能するはずです。

#!/bin/env bash

# Debug code to start on minute boundary and to
# gradually increase maximum payload duration to
# see what happens when the payload exceeds 30 seconds.

((maxtime = 20))
while [[ "$(date +%S)" != "00" ]]; do true; done

while true; do
    # Start a background timer BEFORE the payload runs.

    sleep 30 &

    # Execute the payload, some random duration up to the limit.
    # Extra blank line if excess payload.

    ((delay = RANDOM % maxtime + 1))
    ((maxtime += 1))
    echo "$(date) Sleeping for ${delay} seconds (max ${maxtime})."
    [[ ${delay} -gt 30 ]] && echo
    sleep ${delay}

    # Wait for timer to finish before next cycle.

    wait
done

コツはペイロードを実行する前sleep 30バックグラウンドで開始することです。次に、ペイロードが終了したら、バックグラウンドsleepが終了するのを待ちます。

ペイロードにn数秒かかる場合(ここでn <= 30)、ペイロードの後の待機時間は秒になります30 - n。30秒以上かかる場合、ペイロードが終了するまで次のサイクルは遅延しますが、それ以上は続きません。

そこには、出力を最初からわかりやすくするために、1分の境界から開始するデバッグコードが含まれていることがわかります。また、最大ペイロード時間を徐々に増やして、最終的にペイロードが30秒のサイクル時間を超えていることを確認します(追加の空白行が出力されるため、効果は明ら​​かです)。

サンプルの実行が続きます(サイクルは通常、前のサイクルの30秒後に開始されます)。

Tue May 26 20:56:00 AWST 2020 Sleeping for 9 seconds (max 21).
Tue May 26 20:56:30 AWST 2020 Sleeping for 19 seconds (max 22).
Tue May 26 20:57:00 AWST 2020 Sleeping for 9 seconds (max 23).
Tue May 26 20:57:30 AWST 2020 Sleeping for 7 seconds (max 24).
Tue May 26 20:58:00 AWST 2020 Sleeping for 2 seconds (max 25).
Tue May 26 20:58:30 AWST 2020 Sleeping for 8 seconds (max 26).
Tue May 26 20:59:00 AWST 2020 Sleeping for 20 seconds (max 27).
Tue May 26 20:59:30 AWST 2020 Sleeping for 25 seconds (max 28).
Tue May 26 21:00:00 AWST 2020 Sleeping for 5 seconds (max 29).
Tue May 26 21:00:30 AWST 2020 Sleeping for 6 seconds (max 30).
Tue May 26 21:01:00 AWST 2020 Sleeping for 27 seconds (max 31).
Tue May 26 21:01:30 AWST 2020 Sleeping for 25 seconds (max 32).
Tue May 26 21:02:00 AWST 2020 Sleeping for 15 seconds (max 33).
Tue May 26 21:02:30 AWST 2020 Sleeping for 10 seconds (max 34).
Tue May 26 21:03:00 AWST 2020 Sleeping for 5 seconds (max 35).
Tue May 26 21:03:30 AWST 2020 Sleeping for 35 seconds (max 36).

Tue May 26 21:04:05 AWST 2020 Sleeping for 2 seconds (max 37).
Tue May 26 21:04:35 AWST 2020 Sleeping for 20 seconds (max 38).
Tue May 26 21:05:05 AWST 2020 Sleeping for 22 seconds (max 39).
Tue May 26 21:05:35 AWST 2020 Sleeping for 18 seconds (max 40).
Tue May 26 21:06:05 AWST 2020 Sleeping for 33 seconds (max 41).

Tue May 26 21:06:38 AWST 2020 Sleeping for 31 seconds (max 42).

Tue May 26 21:07:09 AWST 2020 Sleeping for 6 seconds (max 43).

kludgyソリューションを避けたい場合は、おそらくこれがより良い方法です。cronこのスクリプトが実行されているかどうかを定期的に検出し、実行されていない場合は開始するためのジョブ(または同等のもの)が必要です。ただし、スクリプト自体がタイミングを処理します。


(a)同僚の何人かは、kludgeが私の専門だと言います:-)


29
これはすばらしい回避策です。それで、私はそれが不器用さを超越すると思います
質問マーク

14
@ rubo77、実行に1秒未満かかった場合のみ:-) 29秒かかった場合、0:00:00、0:00.59、0:01:00、0:01:59などに発生します。 。
paxdiablo 2015

1
超卑​​劣で、非常に創造的です!
Kラファエル

2
2行目の周りの丸括弧は何ですか?
Nigel Alderton、2018

2
これは、ほんの数分で実行する必要がある特定のタスクのcronの有効性を損なう問題の素晴らしい解決策です。ありがとうございました。
Fiddy Bux

67

できません。Cronの粒度は60秒です。

* * * * * cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''
* * * * * sleep 30 && cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''

この構文はpaxdiabloの構文と同等ですか?または微妙な違いはありますか?
Nicolas Raoul

違いは、バイナリへの元のパスを使用したことです。@paxdiabloは一種のメタ構文を使用しました。(および
サブシェル

1
つまり、の&&代わりに使用します( ; )
Nicolas Raoul

2
ごめんなさい。いいえ、違いがあります。&&オペレータ短絡、以前のものが失敗した場合、チェーン内の次のコマンドが実行されないように。
wildplasser

この細分性は、1分未満の解像度では問題になりません。
フアンイサザ

37

Cronの粒度は分単位であり、何かを実行するために毎秒起動するようには設計されていませんx。繰り返しタスクをループ内で実行すると、必要なことが実行されます。

#!/bin/env bash
while [ true ]; do
 sleep 30
 # do what you need to here
done

54
まったく同じではないことを覚えておいてください。たとえば、ジョブに25秒かかる場合、30秒ごとではなく55秒ごとに開始されます。それは問題ではないかもしれませんが、起こり得る結果に注意する必要があります。
paxdiablo 2012年

7
ジョブをバックグラウンドで実行すると、ほぼ正確に30秒で実行されます。
Chris Koston、2013年

1
一方、[true] do sleep 30#ここで必要なことを行う---------小文字で行う必要があります
テンプル

1
while [ true ]cronは1分ごとに新しいスクリプトを開始するため、同じスクリプトのインスタンスを多数持つ原因にはなりませんか?
Carcamano 2014年

2
sleep $remainingTime残り時間が30からジョブにかかった時間を差し引いた場所で実行できます(30秒以上かかった場合はゼロにキャップします)。実際の作業の前後に時間をかけて、その差を計算します。
mahemoff '15

32

SystemDを搭載した最近のLinux OSを実行している場合は、SystemDタイマーユニットを使用して、スクリプトを任意の粒度レベル(理論的にはナノ秒まで)で実行できます。また、必要に応じて、Cronがこれまでに許可したよりもはるかに柔軟な起動ルールを使用できます。 。sleepクラッジは必要ありません

cronファイルの1行を設定するよりも少し時間がかかりますが、「毎分」以上のものが必要な場合は、努力する価値があります。

SystemDタイマーモデルは基本的に次のとおりです。タイマーは、タイマーが経過したときにサービスユニットを開始するユニットです。

したがって、スケジュールするすべてのスクリプト/コマンドについて、サービスユニットと追加のタイマーユニットが必要です。1つのタイマーユニットに複数のスケジュールを含めることができるため、通常は複数のタイマーと1つのサービスは必要ありません。

次に、10秒ごとに「Hello World」をログに記録する簡単な例を示します。

/etc/systemd/system/helloworld.service

[Unit]
Description=Say Hello
[Service]
ExecStart=/usr/bin/logger -i Hello World

/etc/systemd/system/helloworld.timer

[Unit]
Description=Say Hello every 10 seconds
[Timer]
OnBootSec=10
OnUnitActiveSec=10
AccuracySec=1ms
[Install]
WantedBy=timers.target

これらのユニットを設定した後(/etc/systemd/system上記のように、システム全体の設定の場合、またはで~/.config/systemd/userユーザー固有の設定の場合)を実行してsystemctl enable --now helloworld.timer(サービスではなく)タイマーを有効にする必要があります(--nowフラグはタイマーも開始しますそれ以外の場合は、次の起動またはユーザーログインの後にのみ開始されます)。

[Timer]以下のように、ここで使用されるセクションのフィールドは、次のとおりです。

  • OnBootSec -各起動後、この数秒後にサービスを開始します。
  • OnUnitActiveSec-サービスが最後に開始されてから数秒後にサービスを開始します。これにより、タイマーが繰り返され、cronジョブのように動作します。
  • AccuracySec-タイマーの精度を設定します。タイマーは、このフィールドが設定するのと同じくらい正確で、デフォルトは1分です(cronをエミュレートします)。最高の精度を要求しない主な理由は、電力消費を改善することです。SystemDが次の実行を他のイベントと一致するようにスケジュールできる場合、CPUを頻繁に起動する必要はありません。1ms私は通常セットの精度-上記の例では、理想的ではない1、私のサブ分スケジュールジョブで(1秒)、それは、あなたが「Hello World」のメッセージを示すログを見れば、あなたがいることを見たいということを意味します多くの場合、1秒遅れます。それでよければ、精度を1秒以上に設定することをお勧めします。

お気づきかもしれませんが、このタイマーはCronをそれほどよく模倣していません。つまり、コマンドがすべてのウォールクロック期間の開始時に開始されない(つまり、クロックの10秒目に開始されない)という意味です。その後、20日など)。代わりに、タイマーが切れたときに発生します。システムが12:05:37で起動した場合、次にコマンドを実行したときは12:05:47、12:05:57のようになります。実際の壁時計の精度に興味がある場合は、OnBootSecおよびOnUnitActiveSecフィールドを置き換えて、代わりにOnCalendar、必要なスケジュールでルールを設定します(私が理解している限り、カレンダー形式を使用すると、1秒より速くすることはできません)。上記の例は、次のように書くこともできます。

OnCalendar=*-*-* *:*:00,10,20,30,40,50

最後の注記:おそらくご想像のとおりhelloworld.timerhelloworld.serviceユニットは同じ名前(ユニットタイプのサフィックスを除いたもの)を持っているため、ユニットを開始します。これはデフォルトですがUnit[Timer]セクションのフィールドを設定することでオーバーライドできます。

詳細については、次のURLをご覧ください。


2
私はコメント欄でこのようなより良い答えに出くわします。IMHO、cronのは、スケジュールされたジョブのための定番となっているものの、この答えはスリープのそのない「ハック仕事」以来受け入れられ一つで、必要な間隔/周波数を考慮長時間実行タスクを実行する並列化を危険にさらす必要がある
Qiqo

2
すばらしい答え、選択した答えにする必要があります
GuidedHacking

21

2つのcronエントリは必要ありません。次のコマンドで1つに入れることができます。

* * * * * /bin/bash -l -c "/path/to/executable; sleep 30 ; /path/to/executable"

あなたの場合:

* * * * * /bin/bash -l -c "cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'' ; sleep 30 ; cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''"


11
注:これは、スクリプトの実行に1秒未満かかる場合にのみ正しく実行されます
rubo77

2
Rubo-ジョブが完了するまでに数ミリ秒(ミリ秒またはマイクロ秒ではなく)かかっている場合、30秒ごとに実行して1分あたり2回実行することはできません。したがって、はい、30から始めて、1秒を超える場合は、実行からおよその秒数を引きます。
アンドリュー

2
これは、実行ごとに個別にエラーレポートを受信する場合にも役立ちません。
joeln

joelin-私が与えるコマンドはログまたは出力データの取得を妨げません。質問に対処するためにコマンドを簡略化しました。ロギングをキャプチャするには、ロギングが必要な場合、各コマンドで出力をリダイレクトすることができます(たとえば、script / rails runner -e production '\' 'Song.insert_latest' \ ''は、script / rails runner -e production '\'と記述できます) 'Song.insert_latest' \ '' 2>&1> / path_to_logfileそして、単一のcronエントリ内の各コマンドに対して再度実行できます。
Andrew

13

あなたはこの同様の質問への私の答えをチェックすることができます

基本的に、「runEvery.sh」という名前のbashスクリプトが含まれています。これを1分ごとにcronで実行し、実行する実際のコマンドと実行する頻度(秒)を引数として渡すことができます。

このようなもの

* * * * * ~/bin/runEvery.sh 5 myScript.sh


10

時計を使用:

$ watch --interval .30 script_to_run_every_30_sec.sh

次のようなものを使用でき$ watch --interval .10 php some_file.phpますか?またはwatch.shファイルでのみ機能しますか?
Yevhenii Shashkov 2017年

時計なら何でも走れます。ただし、間隔は次のコマンドの終了と開始の間にあるため--interval .30、1分間に2回は実行されません。つまりwatch -n 2 "sleep 1 && date +%s"、3秒ごとに増分します。
jmartori

注意してくださいwatch、それは、端末なしで動作することができながら(と実行-ので、ターミナルの使用のために設計されたnohup後、ログアウト)または(のような偽の端子とをscreen) -それは、そのような障害からの回復などのcronのような振る舞いのためのアフォーダンスを、持っていません、ブート後の再起動など」
GUSS

9

cronジョブを使用して、秒単位でジョブをスケジュールすることはできません。つまり、5秒ごとに実行するcronジョブをスケジュールすることはできません。別の方法は、sleep 5コマンドを使用するシェルスクリプトを記述することです。

以下に示すように、bash whileループを使用して、5秒ごとにシェルスクリプトを作成します。

$ cat every-5-seconds.sh
#!/bin/bash
while true
do
 /home/ramesh/backup.sh
 sleep 5
done

次に、nohup以下に示すように、このシェルスクリプトをバックグラウンドで実行します。これにより、セッションからログアウトした後もスクリプトが実行され続けます。これにより、backup.shシェルスクリプトが5秒ごとに実行されます。

$ nohup ./every-5-seconds.sh &

4
時間はずれます。たとえば、backup.sh実行に1.5秒かかる場合、6.5秒ごとに実行されます。それを避けるための方法は、たとえば、ありますsleep $((5 - $(date +%s) % 5))
キース・トンプソン

私はnohupを使い始めたばかりですが、あなたの例を実行していると、nohupは「そのようなファイルやディレクトリはありません」を返します。いくつか検索した後、nohupの後に 'sh'を逃したようです。$ nohupをSH ./every-5-seconds.sh&:このような
VHanded

6

fcron(http://fcron.free.fr/)を使用します-数秒で細かく設定でき、cron(vixie-cron)よりも機能が豊富で安定しています。私は以前、1台のマシンで非常に愚かな設定で約60のphpスクリプトを実行するような愚かなことをしてきましたが、それでもそれはうまくいきました!


1
PHP開発者の告白。)
エリック・キガティ2017

3
実際、PHP開発者を可能にするシステムエンジニアの告白.... :)
Adi Chiru 2017

6

dirに /etc/cron.d/

新規にファイルを作成 excute_per_30s

* * * * * yourusername  /bin/date >> /home/yourusername/temp/date.txt
* * * * * yourusername sleep 30; /bin/date >> /home/yourusername/temp/date.txt

30秒ごとにcronを実行します


4

現在、私は以下の方法を使用しています。問題なく動作します。

* * * * * /bin/bash -c ' for i in {1..X}; do YOUR_COMMANDS ; sleep Y ; done '

N秒ごとに実行する場合、X60 / NYNになります。

ありがとうございました。


コマンドがバックグラウンドで起動されるようYOUR_COMMANDSYOUR_COMMANDS &、おそらくに変更する必要があります。それ以外の場合、コマンドに1秒もかからない場合は、次の起動が遅延します。したがって、X = 2およびY = 30の場合、コマンドに10秒かかると、30分ではなく、1分後に40秒後に起動します。Kudusから@paxdiabloへ。
Guss

何らかの理由で、/bin/bash -c部分(引数の引用符を含む)を省略した場合、スクリプトは毎分だけ実行され、反復を無視します(私の場合X=12Y=5)。
abiyi

3

Crontabジョブを使用して、分単位、時間単位、日単位でジョブをスケジュールできますが、秒単位ではできません。代替:

30秒ごとに実行するスクリプトを作成します。

#!/bin/bash
# 30sec.sh

for COUNT in `seq 29` ; do
  cp /application/tmp/* /home/test
  sleep 30
done

crontab -eとcrontabを使用して、このスクリプトを実行します。

* * * * * /home/test/30sec.sh > /dev/null

2
私がこれを正しく理解している場合、このスクリプトは30回実行され、反復ごとに30秒待機します。cronで毎分実行するのはどういう意味ですか?
FuzzyAmi 2017

2

そのスクリプトをサービスとして実行し、30秒ごとに再起動できます

サービスを登録する

sudo vim /etc/systemd/system/YOUR_SERVICE_NAME.service

以下のコマンドを貼り付けます

Description=GIVE_YOUR_SERVICE_A_DESCRIPTION

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
ExecStart=YOUR_COMMAND_HERE
Restart=always
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

リロードサービス

sudo systemctl daemon-reload

サービスを有効にする

sudo systemctl enable YOUR_SERVICE_NAME

サービスを開始する

sudo systemctl start YOUR_SERVICE_NAME

サービスのステータスを確認する

systemctl status YOUR_SERVICE_NAME

1

すべての良い答えをありがとう。簡単にするために、私はcrontabの制御とスクリプトの時分割の混合ソリューションが好きでした。これが、20秒ごと(1分あたり3回)にスクリプトを実行するために行った処理です。Crontab行:

 * * * * 1-6 ./a/b/checkAgendaScript >> /home/a/b/cronlogs/checkAgenda.log

脚本:

cd /home/a/b/checkAgenda

java -jar checkAgenda.jar
sleep 20
java -jar checkAgenda.jar 
sleep 20
java -jar checkAgenda.jar 

1-6は何を表していますか?
Phantom007

@ Phantom007 1-6は月曜日から土曜日を表します。「-」は範囲、「0」は日曜日です。以下は、すべてのフィールドとそれをテストできる場所を非常によく説明している良いリンクです: " crontab.guru/# * _ * _ * _ * _ 1-6"
jfajunior

1

1つのシェルスクリプトを作成して.shファイルを作成する

nano every30second.sh

そしてスクリプトを書く

#!/bin/bash
For  (( i=1; i <= 2; i++ ))
do
    write Command here
    sleep 30
done

次に、このスクリプトにcronを設定します crontab -e

(* * * * * /home/username/every30second.sh)

このcronは.shファイルを1分ごとに呼び出し、.shファイルコマンドは1分に2回実行されます

スクリプトを5秒間実行する場合は、30を5に置き換えて、forループを次のように変更します。 For (( i=1; i <= 12; i++ ))

あなたが任意の秒を選択すると、60 /あなたの秒を計算し、Forループに書き込みます


0

私は同様のタスクを実行し、次のアプローチを使用しました:

nohup watch -n30 "kill -3 NODE_PID" &

数時間、30秒ごとに定期的にkill -3(プログラムのスタックトレースを取得する)する必要がありました。

nohup ... & 

これは、シェルを緩めてもウォッチの実行が失われないようにするためです(ネットワークの問題、Windowsのクラッシュなど)。


0

頻繁にcronを見てください。古くはありますが、非常に安定しており、マイクロ秒まで下げることができます。この時点で私が反対するのは、まだinit.dの外にインストールする方法を考えているところですが、ネイティブのsystemdサービスとしてですが、Ubuntu 18までは、それでもinit.dを使用して問題ありません(距離は後のバージョンで異なる場合があります)。これには、以前のインスタンスが完了しない限り、PHPスクリプトの別のインスタンスが生成されないことを保証するという追加の利点(?)があり、潜在的なメモリリークの問題が軽減されます。


-1

シェルループで実行します。例:

#!/bin/sh    
counter=1
while true ; do
 echo $counter
 counter=$((counter+1))
 if [[ "$counter" -eq 60 ]]; then
  counter=0
 fi
 wget -q http://localhost/tool/heartbeat/ -O - > /dev/null 2>&1 &
 sleep 1
done

でも、それは仮定し60なければなりません30、あなたはそれを移動したい場合がありますwget 内のifそれ以外の場合は、毎秒実行されています、声明。いずれにせよ、これがただ1つより優れているかどうかはわかりませんsleep 30。カウンターではなく実際のUNIX時間を監視している場合は、違いが生じます。
paxdiablo

カウンターの出力をエコーし​​ます。バックグラウンドでwgetを実行しないと、EXCUTE COMMANDによって遅延した時間がわかります。
Lo Vega
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.