MariaDB講座 / イベントでDB処理を予約し、実行結果を確認する

MariaDB Event Schedulerは指定時刻や間隔でSQLを実行します。定義があること、スケジューラーが有効なこと、業務処理が成功したことは別なので、予約情報と実際にできたデータを両方確認します。

適した処理と実行者を選ぶ

短いDB内集計や範囲を限る整理に向きます。外部API、ファイル転送、複数システムの再試行や通知は外部ワーカーが適する場合があります。この例は削除せず一実行一行を追加し、結果を観察します。

appops_labへCREATE TABLE、INSERTとEVENTが必要です。実行者は接続中クライアントではなくイベントのDEFINERなので、権限変更は後の実行へ影響します。時間帯とログ、どのサーバーで仕事を動かすかも決めます。

スケジューラーと時間帯を先に読む

接続内で読み取ります。

SELECT @@GLOBAL.event_scheduler, @@GLOBAL.time_zone, @@SESSION.time_zone;

ONなら実行、OFFでも定義は存在でき、DISABLEDなら起動設定と方針をDBAが確認します。共有サーバーで全体ONにすると他のイベントも動くため、新しい専用実習環境の管理者だけが必要時にSET GLOBAL event_scheduler = ON;を使い、元値を記録します。終了時も自分のイベントを先に止め、他仕事への影響を確認せず全体OFFへ戻しません。

結果表と無効な定義を作る

同名表とイベントが未使用か確認して実行します。

CREATE DATABASE IF NOT EXISTS appops_lab
  CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE appops_lab;
CREATE TABLE event_runs (
  run_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  ran_at DATETIME(6) NOT NULL,
  run_label VARCHAR(40) NOT NULL
) ENGINE=InnoDB;

作成時刻の解釈を+00:00へそろえ、元のセッション値も保存します。

SET @event_saved_time_zone = @@SESSION.time_zone;
SET SESSION time_zone = '+00:00';
CREATE EVENT appops_lab.record_run
  ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 10 SECOND
  ON COMPLETION PRESERVE
  DISABLE
  DO INSERT INTO appops_lab.event_runs (ran_at, run_label) VALUES (UTC_TIMESTAMP(6), 'scheduled-check');

DISABLEで事前実行を防ぎ、ON COMPLETION PRESERVEで一回の実行後も定義を残します。これはデータ保持や再試行の保証ではありません。メタ情報と結果を調べます。

SELECT @@GLOBAL.event_scheduler;
SELECT EVENT_NAME, STATUS, TIME_ZONE, EXECUTE_AT, LAST_EXECUTED
FROM information_schema.EVENTS
WHERE EVENT_SCHEMA = 'appops_lab' AND EVENT_NAME = 'record_run';
SELECT run_id, ran_at, run_label FROM appops_lab.event_runs ORDER BY run_id;

最初はDISABLEDの定義一件、結果は0行です。PCの表示時刻とサーバー側の予約文脈を同一視しません。

有効化と同時に新しい未来時刻を設定する

読む間に元の10秒が過ぎるので、古い一回予約を再利用しません。

ALTER EVENT appops_lab.record_run
  ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 10 SECOND
  ENABLE;

約10秒後に確認SQLを再実行します。厳密なリアルタイムタイマーではないため、時計の完全一致は判定基準ではありません。scheduled-check一行、LAST_EXECUTEDと完了後DISABLEDを確認します。LAST_EXECUTEDは試行の証拠で、業務全体の成功は結果行でも照合します。別接続で実行するため、現在クライアントの影響件数は証拠になりません。

終了時刻を付けて反復と再実行を考える

一回を確認後、必要なら有限の繰り返しへ変えます。

ALTER EVENT appops_lab.record_run
  ON SCHEDULE EVERY 1 MINUTE
  STARTS CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
  ENDS CURRENT_TIMESTAMP + INTERVAL 3 MINUTE
  ENABLE;

実例は実行ごとに一行を追加します。実集計は対象期間の一意キー、再計算や冪等性を定め、再試行で同じ金額を二重加算しないようにします。処理時間が間隔を超えるなら重なりも検討します。複製・昇格時に複数台で同時実行しない所有方針も必要です。

停止して原因と再処理範囲を確認する

未来の起動を止めて定義を読みます。

ALTER EVENT appops_lab.record_run DISABLE;
SHOW CREATE EVENT appops_lab.record_run;

無効化しても実行中の仕事が即座に中断されるとは限りません。scheduler、STATUS、DEFINER権限、TIME_ZONEと時刻、結果がなければエラーログと本体SQLを確認します。不要な実習結果ならイベントを先に削除します。

DROP EVENT appops_lab.record_run;
DROP TABLE appops_lab.event_runs;

同じ接続の時刻設定を戻します。

SET SESSION time_zone = @event_saved_time_zone;

再接続済みなら保存変数に頼らず現状を読みます。失敗した定期処理は止めて欠落・重複の範囲を調べてから変更します。

関連する公式リファレンス