動かざることバグの如し

近づきたいよ 君の理想に

docker composeでコンテナが終了したら全コンテナ終了させる方法

環境

  • Docker 25
  • Docker-compose v2

やりたいこと

Docker-compose環境でAコンテナとBコンテナがあったとする。Aコンテナが何らかの理由で落ちてしまった(終了した)場合に Bコンテナも強制終了させたい。

コード

services:
  app:
    image: thr3a/stress:latest
    command: stress --vm 1 --vm-hang 0 --vm-bytes 4024M
    init: true
    deploy:
      resources:
        limits:
          memory: 50M

  nginx:
    image: nginx
    depends_on:
      app:
        condition: service_completed_successfully

起動するときは必ず --abort-on-container-exit をつけなければならない。そのため -d は併用できない

docker compose up --abort-on-container-exit

解説

解説

この設定では、appnginxという2つのサービスが定義されている。appサービスは、メモリ制限が50Mのthr3a/stress:latestイメージを使用し、特定のコマンドを実行する。一方、nginxサービスは、nginxイメージを使用し、appサービスに依存している。

depends_onの設定により、appサービスが正常に完了するまでnginxサービスは開始されない。しかし、この設定だけでは、appサービスが何らかの理由で終了した場合、nginxサービスは自動的には終了しない。

そこで、docker compose up --abort-on-container-exitコマンドを使用する。このコマンドは、任意のサービスが終了した場合に、他のすべてのサービスを終了させる。つまり、appサービスが終了すると、nginxサービスも自動的に終了する。

ただし、このコマンドはデタッチモード(-dオプション)と併用できないため注意が必要だ。デタッチモードを使用すると、コンテナはバックグラウンドで実行され、ユーザーは他のコマンドを入力できる。しかし、--abort-on-container-exitオプションを使用すると、コンテナが終了するまでシェルはブロックされ、ユーザーは他のコマンドを入力できない。これは、--abort-on-container-exitオプションがコンテナの終了を監視し、必要に応じて他のコンテナを終了させるためだ。このため、-dオプションと併用すると、この監視機能が失われ、期待した動作が得られない可能性がある。

Railsのtime_ago_in_wordsをJavaScriptで実装する

環境

  • ES2024

やりたいこと

Railsにはtime_ago_in_wordsという非常に便利なメソッドがある

# 10分前の時刻を生成
ten_minutes_ago = Time.now - 10.minutes

# time_ago_in_wordsを使用して相対時間を表示
puts time_ago_in_words(ten_minutes_ago)

これをJavaScriptでも実現したい

コード

実はRails公式がJSコードを公開してくれている。

gist:58761

が16年前のコードでvarだったり == だったりと最新のJS仕様についていけてないのでChatGPTにリファクタリングしてもらった

直してもらったコード

export const timeAgoInWords = (from) => {
  return distanceOfTimeInWords(new Date(), from);
};

const distanceOfTimeInWords = (to, from) => {
  const distanceInSeconds = (to - from) / 1000;
  const distanceInMinutes = Math.floor(distanceInSeconds / 60);

  if (distanceInMinutes === 0) {
    return '1分未満前';
  }
  if (distanceInMinutes === 1) {
    return '1分前';
  }
  if (distanceInMinutes < 45) {
    return `${distanceInMinutes}分前`;
  }
  if (distanceInMinutes < 90) {
    return '約1時間前';
  }
  if (distanceInMinutes < 1440) {
    return `約${Math.floor(distanceInMinutes / 60)}時間前`;
  }
  if (distanceInMinutes < 2880) {
    return '1日前';
  }
  if (distanceInMinutes < 43200) {
    return `${Math.floor(distanceInMinutes / 1440)}日前`;
  }
  if (distanceInMinutes < 86400) {
    return '約1ヶ月前';
  }
  if (distanceInMinutes < 525960) {
    return `${Math.floor(distanceInMinutes / 43200)}ヶ月前`;
  }
  if (distanceInMinutes < 1051199) {
    return '約1年前';
  }

  return `${Math.floor(distanceInMinutes / 525960)}年以上前`;
};

サンプルコード

// 現在時刻から10分前のDateオブジェクトを生成
const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000);

// timeAgoInWords関数を使用して相対時間を表示
console.log(timeAgoInWords(tenMinutesAgo));

ちなみに

書き終わってから知ったがDay.jsでも相対時刻の表示はできたっぽい。。。

Day.jsで相対日時を厳密に表示する(thresholds)

Rubyで特定の文字を含むライブラリを一括アップデート

環境

  • bundler 2系

やりたいこと

例えば「rubocop」を含む全ライブラリをbundle updateしたい。

  • rubocop、rubocop-rspec: ◯
  • puma: X

これを一発で実行したい

コマンド

bundle update $(bundle list | grep rubocop | awk '{print $2}')
  • bundle list:現在のプロジェクトでインストールされている全てのgemをリストアップする。
  • grep rubocop:そのリストからrubocopを含む行だけを抽出する。
  • awk '{print $2}':各行からgemの名前だけを取り出す。これは行の2番目のフィールド(スペースで区切られた部分)にある。
  • bundle update $(...):抽出したgemの名前を使ってbundle updateを実行する。これにより、指定したgemだけが更新される。

以上の手順により、rubocopを含む全てのライブラリを一度に更新することができる。これは、特定のgemだけを更新したいときに便利だ。

ただし、他のgemに影響を与えずに更新できるかどうかは、gemの依存関係による。依存関係が複雑な場合、予期しない問題が発生する可能性があるので注意が必要だ。それでも、このコマンドは一部のgemを効率的に更新するための強力なツールと言える。

ドラム式洗濯機のお掃除ベストプラクティス

ドラム式洗濯機を買った

引っ越ししたので洗濯機も新調した。

  • 乾燥まで全自動にさせたいのでドラム式洗濯機必須
  • 温水と洗剤自動注入機能は必須
  • タッチパネルは水回りで壊れやすそうだったのでいらない
  • パナソニックと日立は指定価格制度で高め
  • 日立のらくメンテに惹かれたが半年経たずで乾燥機能が壊れるとか口コミが最悪だったのでなし
  • シャープはデザインが合わなかった

ということで半ば消去法的に東芝ドラム式洗濯機を購入した

TW-127XH3L/TW-127XH3R | 洗濯機・洗濯乾燥機 | 東芝ライフスタイル株式会社 | 洗濯機・洗濯乾燥機 | 東芝ライフスタイル株式会社

だが、この機種も例に漏れず毎日メンテナンスしないとすぐにホコリが詰まって故障してしまうのでメンテナンスを備忘録として記す。

環境

我が家では毎日1回洗濯機を回している。原則温水40度設定でエコモードはOFFにしている。

前提

普段自分は取扱説明書読まないタイプだが、ドラム式洗濯機に関して言えば絶対取扱説明書を細かく目を通しておいたほうがいい

サラッと重要な仕様やお手入れ、便利な設定が書いてあったりする。

乾燥フィルターのお手入れ

picture 0

1番問題なのがコイツ。乾燥自体はすげー神なんだが毎回めちゃくちゃホコリが貯まる。 ただ、フィルターも進化しているようで、自分の機種ではホコリはまとまって捨てやすくなっていた。

それでも細かいのは掃除機等で掃除する必要がある。毎回洗面所に掃除機を持っていくのが面倒だったのでハンドクリーナーを購入した。

ヨドバシ.com - アピックス APIX ハピカル 充電式 2Wayクリーナー アイボリー AHR-606IV 通販【全品無料配達】

picture 4

これはアタッチメントが豊富でType-Cで充電できるのが魅力。音はそれなりにするが乾燥フィルターのホコリはしっかり吸ってくれる。 洗濯機をかける前はこれを使って適当に掃除するようにしている。1週間に1回程度中のフィルター洗っている。

また説明書いわく 乾燥フィルターは2週間に1回は水洗いで掃除するべき と書いてある。乾燥フィルターは完全に乾いていないと装置が誤認識して いつまでも乾いてない判定をしてしまい乾燥が終わらなくなってしまうので長時間洗濯機を回さないタイミングを見計らって洗わないといけない。

排水フィルター

ここも毎回ホコリが貯まる場所。縦型洗濯機でいうくず取りネット的な存在を担っている。

picture 1

洗濯後は濡れているのでそのままにしておくと臭いがキツくなる。洗濯完了後早めに水洗いでホコリを落としたあと、乾かしておくのが良い。 筒フィルターの中の方もホコリがへばりついているので取るのに苦労していたが、東芝の洗濯機の場合 100均のペットボトル洗うスポンジ が楽に掃除できるグッズだった。

picture 2

ペットボトル洗いスポンジ - ダイソーネットストア【公式】

ドアパッキン

picture 3

製品ページでは洗濯時に洗い流すと謳っているが実際には結構ホコリが付着する。 ペーパータオルで取ったり、掃除機で掃除したりしているがこの箇所のベストプラクティスはまだ攻略しきれていない。

洗剤自動投入経路

取り扱い説明書では 2〜3ヶ月に1度はカビないように掃除しろ と書いてある。

  1. 洗剤/柔軟剤タンク内に40度のお湯を入れる
  2. 電源を入れる
  3. 「洗剤」と「洗い」を同時に3秒間押す (柔軟剤のお手入れの場合は「柔軟剤」と「洗い」を同時に押す)
  4. ピピピッとブザーがなる
  5. 「スタート」を押す 所要時間は約12分

洗濯槽洗浄

洗濯槽クリーナーを使うやつ 公式曰く1ヶ月やれと書いてある。

  1. クリーナーをドラムに入れる
  2. 電源を入れて「洗乾」を押し続けて「槽クリーン」を選択
  3. 画面が13Hになるようにする
  4. スタート

循環水シャワー出口

picture 5

ドアパッキンに近い箇所何だろうがまだ攻略できていない。

まとめ

こう書いているとやっぱり毎回メンテするのダルいし普通に縦型洗濯機の方がいいんじゃないの?って思われるかもしれないが、 これを凌ぐほど干す作業がなくなるのは素晴らしい。最高

参考リンク

複数の音声データを持つ動画から特定の音声のみを抽出する方法

環境

やりたいこと

副音声で1つの動画に複数の音声データを持っている動画ファイルがある。

このなかで特定の音声データのみ残してほかは削除したい。映像、音声は変換しない。

コマンド

例えば1番目の音声データのみ残したい場合、

ffmpeg -i input.mkv -map 0:v -map 0:a:1 -c copy output.mkv

コマンドのオプションを簡潔に解説すると、

  • -i input.mkv: 入力ファイルを指定する。
  • -map 0:v: 動画ストリームを指定する。0:vは最初の(0)入力ファイルの全ての動画(v)を意味する。
  • -map 0:a:1: 音声ストリームを指定する。0:a:1は最初の(0)入力ファイルの2番目の音声(a:1)を意味する。
  • -c copy: 入力ストリームをそのままコピーする。これにより、変換処理が不要になる。
  • output.mkv: 出力ファイルを指定する。

ffmpegのmapについて

ffmpegmapオプションは、入力ファイルのどのストリームを出力ファイルに含めるかを制御するためのものだ。mapオプションが指定されない場合、ffmpegは各ストリームタイプ(動画、音声、字幕)の最初のストリームを選択する。しかし、特定のストリームを選択したい場合や、複数のストリームを出力したい場合には、mapオプションを使用する。

一括で処理する場合

IFS=$'\n'; for f in *.mkv; do ffmpeg -i $f -map 0:v -map 0:a:1 -c copy -y output/$f; done

参考リンク