@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Bash で C-p が効かないときの調べ方

$ bind -p | grep previous-history
"\C-p": previous-history
"\eOA": previous-history
"\e[A": previous-history
[ubuntu@ip-xxx-xx-xxx-x:~]$ bind -p | grep previous-history
"\eOA": previous-history
"\e[A": previous-history

C-p が無ければ、キーバインドが設定されていないということ。 \eOA\e[A は Up Arrow キーを表すらしい。

zsh-like history in bash - Stack Overflow

Bash/Zsh で C-p / Ctrl-p を押したらコマンドのヒストリを一個戻るのが当然だと長年疑いもせずにきたが、必ずしもそうではないようだ。

単純な理由だった。 ~/.bashrc で set -o vi してある環境だった。

Google Discover その後

知人から「暇つぶしには Google ニュースのアプリもあるよ」と教えてもらい、試しにそちらを使い始めた。

以前試したときは、出てくる記事が Discover と似ていて重複も多く(同じ Google アカウントなので当然だが)、あえて別アプリを使う必要性を感じなかった。しかし今回はむしろ好都合といえる。

ついでに iOS の「スクリーンタイム」と組み合わせることにした。アプリ毎、カテゴリ毎に一日の使用時間制限を設けられるのだ。 Google アプリが使用時間制限にひっかかっていざというとき検索できないと困りそうだが、 Google ニュースアプリなら問題ないだろう、という算段。

数日使ってみた感じだと、不思議と Discover よりも「延々見てしまう」感覚が薄い。あくまでニュースアプリなので一般的なニュース記事も表示されており、全体的な情報量も多いので、嗜好性にマッチした記事の割合が少なく感じられ、興味をそそられないのかもしれない。単にアプリの利用機会がまだ少ないため、嗜好性の学習が不十分なのかもしれない。 Digital Wellbeing としては良いことだけど、やや物足りないところはある。

もう少し自分の行動パターンを分析してみると、検索のついでにブラウジングをして関係ない記事を読みふけって時間を使っているようだ。検索の起点は Google アプリなので、結局これを検索ツール兼ブラウザ兼ニュースリーダーとして使っているのが実態だともいえる。 Google ニュースアプリから気になるトピックについて Web 検索することはないので、使い勝手の違いによる差を「物足りなさ」という違和感で表現したのかもしれない。

とすると、 Google アプリの Discover を許可しつつ「スクリーンタイム」による使用時間制限を設け、おすすめコンテンツ閲覧だけでなく Web 検索きっかけのブラウジングも含めて広義の暇つぶし時間を減らすのでよいのかもしれない。

iOS スマート句読点をオフにした

設定→一般→キーボード→スマート句読点 をオフに。

半角ハイフンを2連続で入力すると全角ダッシュに自動変換されてしまうやつ。鬱陶しくて困っていた。

iPadで英字入力しているときにで2回連続半角ハイフン"-"を打つと全角ハイフン"—"に勝手に変換されてしまう問題 - Qiita

【iPhoneスーパーあるある】ハイフンや引用符を自動で変換!? iOS 11「スマート句読点」機能って何? | GetNavi web ゲットナビ

TIL: 数値をあえて文字列型で保存することがある

列1 列2 列3 列4
eb2c0958-991c-5f26-4d99-8214518fbb8a a 20000 5000
66a08082-ebd0-6de2-c4e8-6388df00e4e5 b 20000 5000

このようなデータを持つ CSV ファイルをパースして RDBMS のテーブルに保存する。列2の値がaならテーブルAに、bならテーブルBに保存する。

テーブルAの各行は、列3と列4の値を数値計算に利用する。テーブルBの各行は、行が存在することにのみ意味があり、列3も列4も数値計算には利用しない。

このような前提で、テーブルBの列3と列4のデータ型が文字列型になっていた。テーブルAの列3と列4は数値型なのにだ。

テーブルA

列名 データ型
列1 text
列2 text
列3 int
列4 int

テーブルB

列名 データ型
列1 text
列2 text
列3 text
列4 text

CSV ファイルの形式上は同種のデータを保存するのだから、両方のテーブルでデータ型は一致しているべきではないのか?

と疑問に思ったので質問すると、「テーブルBの列3と列4は数値計算に用いないため、あえて文字列型にしている」という回答で、なるほどと思った。動的型付けの言語ではこういう設計はしないかもね、とも*1

文字列型の列に数値が入っているとき、それを用いて数値計算するためには型を変換しなければならない。 SQL であれプログラミング言語であれ、もし実際に型変換をした上で計算するようなコードを書けば、明らかに目立つ。それが狙いだ、と解釈した。

全く利用するあてのないデータならテーブルに取り込まなければよいのでは?とも思ったが、将来必要にならないとも限らないし、スナップショットとして完全なデータを保存したい気持ちもわかる。テーブルAと比べてテーブルBの列が少なければ少ないで、なぜ列を減らしたのか?という疑問に繋がる。

折衷案として、不要なデータでも取り込んでおくが、そのデータを意味のある計算に用いるミスを犯しにくくするためにあえて文字列型で保存する、という設計には一理あり、現実的だと思った*2

*1:言語特性というよりは設計者の思想による部分が大きいとは思う。ちなみにこのテーブルのデータは主に Go 言語から利用する

*2:テーブル定義を見ただけでは意図に気付きづらく、誤りであると誤解しやすいので、コメント等で「数値計算に用いないようにあえて文字列型にしている」と書き添えてあるとよい、とフィードバックした

mackerel で cron ジョブの所要時間を監視するアイデア

cron ジョブを監視したい。監視したい項目は以下。

  1. cron ジョブの実行が開始されたかどうか
  2. cron ジョブが正常終了したかどうか
  3. cron ジョブの所要時間

このような課題を解決するソリューションとして Dead Man’s Snitch を使ったことがあるが、他にも複数の類似サービスが存在する。 Cron Job Monitoring というジャンルのようだ*1

Dead Man’s Snitch は 1 の監視に主眼をおいたサービス(だと思う)。 Cronitor3 の監視もカバーしているっぽい(が試してはいない)。他のサービスもおそらく似たようなものだろう。

cron ジョブ監視専門のサービスを導入するのも良いが、 mackerel で実現できないか、と思ったので考えてみた。

1 と 3 は、

  1. cron ジョブの所要時間を計測してサービスメトリックとして投稿する
  2. そのメトリックに対する監視ルールとしてサービスメトリック監視を作成し、サービスメトリックの途切れ監視を有効化する

という組み合わせで監視できる。

2 はmkr wrap コマンドで監視できる。 cron ジョブとして実行するアプリケーションの実装次第で Sentry のようなエラー監視システムに通知することもできる(そうした方が良いだろう)。

試してみた設定やプログラムは以下。 Production 環境で運用する場合は、計測とメトリック投稿を担う wrapper コマンドを用意したり、 cron ジョブの「突き抜け」が発生しないようにロックをかけたりする必要があるだろう。

crontab

* * * * * /usr/bin/time -f '\%e' -o /tmp/elapsed.txt mkr wrap -- ruby cronjob.rb >/tmp/cronjob.log 2>&1; ruby metric.rb

cronjob.rb

ランダムに数十秒かかるコマンド、ということでこんな風にした。余談だがdd(1) で空ファイルを作るときは /dev/zero より seek - flatlineの日記らしい。

#!/usr/bin/env ruby
exec "dd if=/dev/zero of=/tmp/a.dat bs=1MB count=#{[1,1,2,3,5].sample}K"

metric.rb

#!/usr/bin/env ruby
require 'json'
elapsed = File.read('/tmp/elapsed.txt').to_f.ceil
data = [{name: "Cronjob.elapsed", time: Time.now.to_i, value: elapsed}]
File.write('/tmp/metric.json', data.to_json)
apikey = File.read('/etc/mackerel-agent/mackerel-agent.conf').scan(/^apikey\s+=\s+"(.*)"$/)[0][0]
system %!curl https://api.mackerelio.com/api/v0/services/test/tsdb -H 'X-Api-Key: #{apikey}' -H 'Content-Type: application/json' -X POST -d @/tmp/metric.json!

サービスメトリックのグラフの例。縦軸の単位は秒。

f:id:a666666:20200819021418p:plain

アラート画面の例。

f:id:a666666:20200819022218p:plain


1 と 2 は同じことだともいえるし、違うことだともいえる。 Cron Job Monitoring サービスは * * * * * command && curl https://example.com/a78e9dd/complete のように、コマンド実行後に所定の URL へリクエストを送信することで cron ジョブの正常終了を通知する API インタフェースを用意している。これは簡単に使えるが、 && を使うので 1 と 2 の監視を厳密に区別できない(ジョブが kick されなかったことと、 kick されたが異常終了したことの差がわからないはず)。 mkr wrap は 2 の監視をより精緻に行う方法だといえる。

所要時間を監視したい動機は、例えば外部システムと通信するプログラムなど、所要時間の見積もりがしづらい場合がある、というのが一つ。次に、データ量に応じて徐々に所要時間が伸びる場合がある、というのが一つ。いずれも実行開始から一定時間を過ぎたら graceful shutdown させる仕組みを用意した方が良いが、そこまで作り込むのか?という論点はあるし、所要時間を減らすチューニングをするにせよ、 cron の実行間隔を伸ばすにせよ、一回の実行にどのくらい時間がかかるのか?を計測してからの方が良い解決方法を判断できるのは間違いない。

*1:正直、ジャンルがあるほど盛り上がってるとは思わなかった