フォールトトレラントクローンの交換

フォールトトレラントクローンの交換

私はcrondを置き換えるか、拡張機能を探しています。

私が持っていたい機能は耐障害性です。たとえば、指定された時間にコンピュータの電源が入らず(停電など)、ジョブの実行に失敗した場合、またはジョブが正常に実行されなかった場合(例:rc!= 0)(アクセス不足のため)、インターネットに接続する)関連ソフトウェアは、次のスケジュールされた実行まで定期的に再試行する必要があります。

持つ価値がある他の機能:

  • RESTインターフェースなどによるリモコン
  • より良いロギング

そのようなソフトウェアが利用できない場合は、既存のソフトウェアを拡張するのか、それとも最初から何かを書くことのどちらがより良いアイデアであるのかを正しい方向に伝えることができる人はいますか?

ベストアンサー1

1日に1回以上実行する必要があるタスクがいくつかあります。私がすることは、これらのタスクのスクリプトを毎時間(またはより頻繁に)開始することです。その後、スクリプト自体がディスク上のステータスファイルを調べて、そのジョブが実行されたことを確認します。

状態ファイルが存在し、最新の状態である場合、スクリプトは終了します。

ファイルが古すぎるか(つまり、1日前に最後に記録された)、存在しない場合は、スクリプトが実行され、正常終了時にステータスファイルが作成されます。

この機能を既存のプログラムに構築できない場合は、プログラムを実行する必要があるかどうかを確認し、必要に応じてそれを呼び出して、成功時にステータスファイル(終了値、解析された出力)を作成するラッパースクリプトを作成します。


/usr/local/bin/catchup.simple:

#! /usr/bin/env python

"""
first parameter is a path to a file /..../daily/some_name
That is a status/script file and the /daily/ indicates it needs to run at least
once a day (after reboot, after midnight).

The rest of the parameters is the command executed and its parameters.
If there are no more parameters beyond the first the actual status
file is /..../daily/some_name.status and is expected to be updated by calling
the /....daily/some_name script (which has to be executable). That
script doesn't need to know about the frequency and gets called with
the status file as first (and only) argument.

Valid directory names and their functioning:

   /daily/  run once a day (UTC)
   /hourly/ run once an hour

The actual scheduling and frequency to check if running is necessary, is
done using a crontab entry:

CU=/usr/local/bin/catchup.simple
CUD=/root/catchup

# month, hour, day_of_month, month day_of_week command
*/5 * * * * $CU $CUD/daily/getlogs curl ....

If mulitple days (or hours) have gone by, no runs are made for skipped
days.

If subprocess.check_output() fails the status file is not updated.
"""

import sys
import datetime
import subprocess

verbose = False  # set to True to debug

def main():
    if len(sys.argv) < 2:
        print 'not enough parameters for', sys.argv[0]
        return
    if len(sys.argv) == 2:
        status_file_name = sys.argv[1] + '.status'
        cmd = [sys.argv[1]]
    else:
        status_file_name = sys.argv[1]
        cmd = sys.argv[2:]

    freq = sys.argv[1].rsplit('/', 2)[-2]
    if verbose:
        print 'cmd', cmd
        print 'status', status_file_name
        print 'frequency', freq
    try:
        last_status = datetime.datetime.strptime(
            open(status_file_name).read().split('.')[0],
            "%Y-%m-%dT%H:%M:%S",
        )
    except (IOError, ValueError):
        last_status = datetime.datetime(2000, 1, 1)

    now = datetime.datetime.utcnow().replace(microsecond=0)
    if verbose:
        print last_status
        print 'now', now.isoformat()
    if freq == 'daily':
        if last_status.date() < now.date():
            subprocess.check_output(cmd)
        elif verbose:
            print 'already done today'
    elif freq == 'hourly':
        if last_status.date() < now.date() or \
           last_status.date() == now.date() and \
           last_status.hour < now.hour:
           subprocess.check_output(cmd)
        elif verbose:
            print 'already done this hour'

    with open(status_file_name, 'w') as fp:
        fp.write(now.isoformat())

if __name__ == "__main__":
    main()

おすすめ記事