※ただしAWS Event Bridge
Show cron schedule. USAGE: curl cronplan.in -d '5 0 * * ? *' curl cronplan.in -G --data-urlencode 'e=5 0 * * ? *' see http://cronplan.in?e=5+0+*+*+?+*
$ curl cronplan.in -d '5/3 0/3 ? * FRI *' Fri, 21 Oct 2022 00:05:00 Fri, 21 Oct 2022 00:08:00 Fri, 21 Oct 2022 00:11:00 Fri, 21 Oct 2022 00:14:00 Fri, 21 Oct 2022 00:17:00 Fri, 21 Oct 2022 00:20:00 Fri, 21 Oct 2022 00:23:00 Fri, 21 Oct 2022 00:26:00 Fri, 21 Oct 2022 00:29:00 Fri, 21 Oct 2022 00:32:00
追記3
もろもろ作り直した
追記2
いろいろ間違っていた…
追記
1-10/3
とか MON-FRI/3
とかを忘れていたので作り直し…
cron式をパースするGolangのライブラリを書いた。
モチベーションとしては、Amazon EventBridgeのcron式を書くときに毎回JSTからUTCに変換するのがめんどくさくて「いつの日かterraformにユーザー定義関数が追加されるときに備えて(くるのか?)タイムゾーンをシフトするライブラリを書こう」という感じで始めた。
パーサー自体は alecthomas/participle でサクサク書けたが
時間をシフトする処理は難しくて諦めた。
たとえば 0 5-10 ? * FRI *
のようなJSTのcron式をUTCに直すと 0 20-23 ? * THU *
と 0 0-1 ? * FRI *
の2つに分かれる。cron式の分解と合成のうまいやり方が思いつかなかった。自分が無知なだけで良い方法があるのかも
EventBridgeの仕様を参考にしたが、いくつか知らない仕様があって勉強になった。
たとえば
0 0 ? * 3#2 *
: 毎月の第二水曜日の00:00に実行0 0 8W * ? *
: 毎月8日に一番近い平日に実行
0 0 L * ? *
: 毎月の最終日の00:00に実行0 0 ? * L *
: 毎週の最終日、つまり土曜日の00:00に実行など
オラクルのドキュメントでも同様の記号が書かれていたので、AWSだけの仕様ではない…ような気がする(オラクルのほうのC
の意味はわからなかった)
時間のシフトを計算する処理は諦めたが、ASTだけあってもあまり有用ではなさそうなので、ついでとある時刻がcronのスケジュールにマッチするかどうか判別する機能も付けてみた。しかし曜日(Day of week)フィールドの処理で結構ハマってしまった…
増分の表現は、分子≒オフセット・分母≒増分と、分数のようなかたちで書く。(改めて書くほどのことでもないが)
*/3
は 0/3
と同じで、実行される時間は 0 3 6 9 …
となる。1/3
の場合は1 4 7 10 …
*/3
は 1/3
と同じ。実行される日付は 1 4 7 10 13…
*/3
は 1970/3
と同じになる模様(AWSコンソール調べ)曜日(Day of week)フィールドの場合、*/3
は 1/3
と同じ結果になる。
曜日の数値 1-7 は MON-SUN にマップされているので MON(1) THU(4) SUN(7)…
となると思いきや、実はSUN始まりで SUM(0) WED(3) SAT(6)…
となる。
曜日(Day of week)を考えないと、時刻をnとしたときに n % (分母) == (分子)
という計算でその時刻がcronを実行する時刻なのか判別できるが、曜日(Day of week)は他と分子の扱いが違うので特別な処理を挟む必要があって、だいぶ実装に時間が取られてしまった。
これLinuxでも同様の動作なのかな
あと、EventBridgeだとMON-SUNが1-7に対して、プログラム上だとSUN-SATが0-6になっているので細々した変換が必要で、そちらもすこしめんどくさかった。
RDSのインスタンスクラスごとのメモリ量を習得するterraform provider。
インスタンスクラスごとにデータソースを定義するか、
data "rds_db_instance_memory" "rds" { instance_class = "db.t3.micro" } #=> { # "instance_class" = "db.t3.micro" # "memory" = 1 # }
インスタンスクラスごとのメモリ量のマップを定義するデータソースを使って、メモリ量を取得できる。
date "rds_db_instance_memory_map" "rds" { } #=> { # "memory_by_instance_class" = tomap({ # "db.m1.large" = 7.5 # "db.m1.medium" = 3.75 # "db.m1.small" = 1.7 # ... # }) # }
あと、クラスタのインスタンスも合わせたすべてのDBインスタンスのインスタンスクラスを取得するデータソースも追加した。
data "rds_db_instances" "rds" { } #=> { # "instances" = tolist([ # { # "instance_class" = "db.t3.micro" # "name" = "database-1" # }, # { # "instance_class" = "db.t3.small" # "name" = "database-2" # }, # ... # ]) # }
terraformでDatadogのアラートを設定するときに、メモリ使用量の閾値をパーセンテージで設定したいときとかに使う想定。
Vantageというクラウドコストの最適化サービスをやっている会社のOSSのよう。
https://instances.vantage.sh/rds/instances.json からJSONでRDSの情報を取得できるので
curl -sSfL https://instances.vantage.sh/rds/instances.json \ | jq 'map({key: .instanceType, value: .memory | tonumber}) | sort_by(.key) | from_entries'
see https://tech.kanmu.co.jp/entry/2022/12/04/131536
log_statement=all
を設定するとpostgresql.logにクエリログされる。
$ cat postgresql.log 2022-05-30 04:59:41 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG: statement: select now(); 2022-05-30 04:59:46 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG: statement: begin; 2022-05-30 04:59:48 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG: statement: insert into hello values (1); 2022-05-30 04:59:50 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG: statement: commit; ...
これを自作のツールposlogでndjsonに変換。
log_min_duration_statement
で出力されたログもパースできた…はず。
$ poslog postgresql.log > data.jsonl $ cat data.jsonl {"Timestamp":"2022-05-30 04:59:41 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" select now();"} {"Timestamp":"2022-05-30 04:59:46 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" begin;"} {"Timestamp":"2022-05-30 04:59:48 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" insert into hello values (1);"} {"Timestamp":"2022-05-30 04:59:50 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" commit;"} ...
-fingerprint
オプションを付けるとpt-fingerprintのようなinsert into hello values(?+);
という感じのFingerprintフィールドも付与される。
「SELECTだけ」みたいなテストデータのフィルタリングに使えると思う。
あとは、似たようなクエリの集計とか。
また、-fill-params
を付けるとStatementフィールドのプレースホルダー $1
$2
…が実際の値で置換される。*1
自作のツール qrn を使って、上記ndjsonをテストデータとした負荷テストを実行できる。
https://github.com/winebarrel/qrn
こんな感じ。
qrn -dsn "postgres://pgx_md5:secret@localhost:5432/pgx_test" \ -data data.jsonl -rate 5 -time 300 -nagents 10
上の場合、5エージェント(ユーザー)で5分間、エージェントごとに5 qpsでDBに負荷を与える。
テストデータを複数与えるとエージェントごとに異なるテストデータを実行できるが、簡易化のために -commit-rate
というオプションを用意していて、エージェントがNクエリ実行するごとにcommit; begin
を実行して新しいトランザクションを開始することができるようにしている。
ridgepoleの1.0.2でパーティショニングの対応が入ったのですが、これを削除することを考えています。 理由としては、パーティショニングの機能は多岐にわたりそのすべてをサポートするのは難しいのですが 現状では本体に密結合になっているため、オプショナルな動作にすることができず、 サポートされていない機能を使おうと思うとridgepoleそのものが使用不可になる状態のためです。
オプショナルな動作にするための改修を進めたいのですが、ちょっと時間がとれず いったんすべてをrevertすることを考えてます。
6月中にはなにか対応入れます
PR: https://github.com/ridgepole/ridgepole/pull/392
パーティショニングのサポートを削除しました https://t.co/ohua0Gypsv
— Genki Sugawara (@sgwr_dts) 2022年6月18日