shellでTTL付きのキャッシュをしたい
2017-05-04
QiitaZshshellこんな感じ
sleep 3 ; echo
の結果を最大 5 秒間キャッシュしている様子。
キャッシュの実装
実装はこのあたりに置いてある。
TTL 付きのキャッシュを実装するにあたり、シェルで実現するならファイルに保存しておいて、作成日時はそのファイルのメタ情報を利用すれば楽。
また、やろうと思えば更新日時と作成日時がどちらも取れるので、細かい TTL の実装も可能。
stat -c %Y
コマンドで指定したファイルの最終更新日時の epoch 秒を取得できる。
それと現在時刻を比べて指定した時間より経過していたら...という処理を書くことで TTL を実装する。
stat
を使ってファイルの有効期限判定するには以下のようにする。
$ touch -d '1day ago' hoge.txt
$ [ $(( $(date +%s) - $(stat -c %Y hoge.txt) )) -gt $((60 * 60 * 25)) ] && echo 'true' || echo 'false'
false
$ [ $(( $(date +%s) - $(stat -c %Y hoge.txt) )) -gt $((60 * 60 * 23)) ] && echo 'true' || echo 'false'
true
キャッシュを保存するファイルのパスと TTL、実行するコマンドを渡せるようにするとこんな感じになった。
# TTL的に無効かどうか
function is_too_old() {
local file=$1
local ttl=$2 # seconds
if [ -f $file ]; then
[ $(( $(date +%s) - $(stat -c %Y "$1") )) -gt $ttl ]
else
false
fi
}
# TTLを考慮して読み出す
function read_from_cache() {
local cache=$1
local ttl=$2 # seconds
local command=$3
if $(is_too_old $cache $ttl);then
local result=$(sh -c "$command")
if [ -z $result ]; then
return
else
echo $result > $cache
fi
fi
cat $cache
}
ちなみに Mac だと gnubin を入れる必要がある。 テキスト処理のための標準的なコマンド群の OS X への導入手順 - Qiita
コードを読めばわかるが、例えばgcloud projects list
の結果を 1 日キャッシュするには、
read_from_cache ./cache.txt $((60 * 60 * 24)) "gcloud projects list"
みたいにやれば良い。
"読み込み中"の表示
昔書いた記事に大体ある。 Zsh で長い処理をしている間に読込中を表示する - Qiita
loading コマンドはgithubにおいてある。
読み込み中を表示するあたりの実装はこうなる。
# job制御を無効化してバックグラウンド実行しているプロセスのIDが表示されるのを防ぐ
set +m
# loadingをバックグラウンド実行して表示
loading 1000 &
local loading_pid=$!
# 何か重い処理をする
local result=$(sh -c "$command")
# loadingを消す
kill -INT $loading_pid &>/dev/null
# loadingがkillされるのを待つ
sleep 0.1
# job制御を有効に戻す
set -m
ジョブ制御を無効にしてプロセス ID が表示されてしまうのを防ぐのがポイント。
$ sleep 10000 & # IDが表示される
[1] 89535
$ kill $! # IDが表示される
[1] + terminated sleep 10000
$ set +m
$ sleep 10000 & # IDが表示されない
$ kill $! # IDが表示されない
$ set -m
from: https://qiita.com/petitviolet/items/6c68cf414050fa8b83d6