りんごとバナナとエンジニア

エンジニア修行の記録

RedashアラートのRearm Secondsとは何をするものなのか

Redashを使っていて特に便利だと感じるのがアラート機能。うちの会社では、自社サービスの異常値検知のためにアラート機能を多用している。
しかし、アラートの設定画面にある Rearm Seconds という項目は、公式サイトの説明が少なく、どのような動きをするのかよくわからなかった。そこで、実際にコードを見て仕様を確かめることにした。

2019/02/13現在、アラートを制御するコードは以下にまとまっている。

github.com

@celery.task(name="redash.tasks.check_alerts_for_query", time_limit=300, soft_time_limit=240)
def check_alerts_for_query(query_id):
    logger.debug("Checking query %d for alerts", query_id)

    query = models.Query.query.get(query_id)

    for alert in query.alerts:
        new_state = alert.evaluate()

        if should_notify(alert, new_state):
            logger.info("Alert %d new state: %s", alert.id, new_state)
            old_state = alert.state

            alert.state = new_state
            alert.last_triggered_at = utils.utcnow()
            models.db.session.commit()

            if old_state == models.Alert.UNKNOWN_STATE and new_state == models.Alert.OK_STATE:
                logger.debug("Skipping notification (previous state was unknown and now it's ok).")
                continue

            notify_subscriptions(alert, new_state)

Redashは、アラートに登録されたクエリの実行結果をceleryが定期的に取得し、アラートを起動させるかどうかを決めている。new_state には、アラートの状態(OK_STATE, TRIGGERED_STATE, UNKNOWN_STATE)のいずれかが入る。そして、クエリの結果に応じた状態を一旦 new_stateに入れたうえで、 should_notify関数で実際にアラートを動かすか判定している。もし True と判定されれば、 alert.state = new_stateというように状態を更新し、 notify_subscription 関数の処理でアラートが通知される。
ここで鍵になるのが should_notify関数の役割。このメソッドは以下のようになっている。

def should_notify(alert, new_state):
    passed_rearm_threshold = False
    if alert.rearm and alert.last_triggered_at:
        passed_rearm_threshold = alert.last_triggered_at + datetime.timedelta(seconds=alert.rearm) < utils.utcnow()

    return new_state != alert.state or (alert.state == models.Alert.TRIGGERED_STATE and passed_rearm_threshold)

Rearm Secondsの欄に値を入れると、その値は alert.rearmに入る。そして、 passed_rearm_threshold には、アラートが前回起動した時刻から alert.rearmで指定した秒数が経過しているかどうかが True または Falseで入る。

これをふまえて最終行を見ると、以下のいずれかの時にアラートが起動することがわかる。

  • クエリの実行結果が、元々のアラートの状態とは異なるとき
  • 元々のアラートの状態が TRIGGERED_STATE で、かつ前回起動時刻からRearm Seconds以上が経過しているとき
    • Rearm Secondsを指定していないときは、上記は無条件でFalseとなる(passed_rearm_thresholdのデフォルト値がFalseであるため)

つまり、例えば Rearm Seconds3600 と入れておけば、異常な状態が1時間経っても継続しているときは再度通知してくれる。アラートがTRIGGEREDになっていなければ、Rearm Secondsが指定されていても再度通知されることはない。

フラグを駆使することで、状態管理のコードが思った以上に短くまとまっていて驚いた。変数名はもっと改良しても良さそうだが、これもスマートな書き方で良い。