逆引き:ホスティング・非同期・音声環境
ホスティング、24時間稼働、非同期処理、実行環境、音声Bot、ffmpeg、VC接続の問題を整理します。
この記事で分かること
- 起動コマンドとプロセス種別
- 環境変数とToken読み込み
- build/deploy/runtimeログの分離
- 永続化とDBの扱い
- イベントループの前提
- awaitとtaskの違い
コミュニティの相談ログを匿名化・一般化し、ホスティング・非同期・音声環境の切り分けを整理した逆引きです。
ホスティング・24時間稼働
Botがオンラインにならない
本番にデプロイしたのにBotがオンラインにならない時の初動です。
どこまで進んだか
buildが成功したのか、deploymentが起動したのか、runtimeで例外が出たのかを分けます。オンライン表示だけで判断せず、起動ログとreadyログを見ます。
Discord側と環境側を分ける
Token、Intent、サーバー導入、権限の問題と、起動コマンド、環境変数、依存関係の問題を分けます。
確認ポイント
- build成功
- start command
- Token環境変数
- readyログ
- runtime例外
参考(公式ドキュメント)
起動コマンドとプロセス種別
Procfile、start command、npm scripts、worker/webの違いを確認します。
何を起動するか
BotはHTTPサーバーではなく常駐workerとして動かすことがあります。ホスティング先がどのコマンドを実行しているか、Procfile、package.json scripts、start commandを確認します。
環境変数展開
start commandで環境変数を使う場合、ホスティング先やDockerfile/Nixpacksの実行形式によって展開方法が変わるため、公式ドキュメントで確認します。
確認ポイント
- Procfileの場所
- package.jsonのstart
- RailwayのStart Command
- worker/webの扱い
参考(公式ドキュメント)
- https://docs.railway.com/guides/start-command
- https://devcenter.heroku.com/articles/procfile
- https://docs.npmjs.com/cli/using-npm/scripts/
build/deploy/runtimeを分ける
同じ「デプロイ失敗」でも見るログが違います。
build log
依存関係のinstall、Python/Node.jsのバージョン、native module、ffmpegなどの失敗はbuild logに出ます。
runtime log
Token未設定、Intent、権限、外部API接続、Botコードの例外はruntime logに出ます。deploy成功後に落ちる場合はruntime側を見ます。
確認ポイント
- build log
- deployment status
- runtime log
- 直前の変更
参考(公式ドキュメント)
git push / GitHub連携で失敗する
コードが本番へ届く前の失敗を分けます。
pushとdeployは別
git pushが失敗しているのか、push後のbuildが失敗しているのかを分けます。GitHub連携では、対象branch、monorepo root、build commandの認識も確認します。
戻せる状態にする
本番で直す前に、直前のcommit、環境変数変更、依存更新を分けて戻せるようにします。
参考(公式ドキュメント)
- https://docs.railway.com/deployments/reference
- https://devcenter.heroku.com/articles/how-heroku-works
ffmpeg・native module・OS差
ローカルで動く依存関係が本番で落ちる時の確認です。
ローカルとの差
ffmpeg、opus、node-gyp、glibc、OSパッケージなどはローカルと本番で差が出ます。エラーが出た層をDiscordライブラリ、音声依存、OSパッケージに分けます。
インストール方法
Dockerfile、Nixpacks/Railpack、buildpack、VPSのaptなど、ホスティング先に合った方法で依存関係を入れます。
参考(公式ドキュメント)
環境変数と秘密情報
TokenやDB URLが本番で読めているか確認します。
値を出さない
環境変数名、未設定、空文字、別環境向け値を確認します。値そのものはログやスクリーンショットへ出しません。
反映タイミング
変数の追加や変更後に再デプロイが必要な場合があります。ホスティング先の反映手順を確認します。
確認ポイント
- 変数名
- secretの値をログに出さない
- 再デプロイ
- Token再生成の要否
参考(公式ドキュメント)
24時間稼働と再起動
常駐Botの起動し続ける前提を確認します。
常駐プロセス
Botは一度起動して終わるscriptではなく、Gateway接続を維持する常駐プロセスです。ホスティング先が常駐workerをどう扱うか確認します。
落ちた時
自動再起動があっても原因は消えません。落ちた時刻、例外、メモリ、外部API失敗を記録します。
再起動だけで終わらせない
再起動で直ったように見える場合も、根本原因をログから確認します。直前の変更、依存更新、環境変数変更を戻せるようにしておくと、障害時にロールバックで切り分けられます。
ホスティング移行(Heroku/Glitch/Railwayなど)
ホスティング先を移す時の前提差を確認します。
起動コマンド
Procfile、start command、package scripts、runtime指定を見直します。移行先で同じ書き方が通じるとは限りません。
永続化
ファイル保存、DB、ログ保持、無料枠などの前提が変わる場合があります。移行前に永続化が必要なデータを洗い出します。
確認ポイント
- 起動コマンドの指定方法
- 環境変数の移し替え
- ファイル保存とDBの前提
- 無料枠・スリープ仕様の差
永続化とDB
ファイル保存とDBを混同しない確認です。
ファイル保存の限界
ホスティング環境によってはローカルファイルが再デプロイや再起動で消える前提があります。設定やユーザーデータはDBや外部ストレージへ逃がします。
DB接続
DB URL、接続数、migration、バックアップ、接続失敗時のBot応答を分けます。
確認ポイント
- 一時ファイルか永続データか
- DB URL
- 接続プール
- バックアップ
非同期・実行環境
イベントループ
Notebookや既存loopで起動エラーが出る時の確認です。
通常起動で比べる
Botはまずターミナルや本番環境の通常起動で確認します。Notebook固有のloop問題をBot本体の問題と混ぜないようにします。
awaitの位置
非同期関数を呼ぶだけでは実行されません。await、task、runの違いを確認します。
参考(公式ドキュメント)
長時間処理
応答期限やheartbeatを詰まらせない設計です。
Interactionは先に応答
重い処理はdeferしてから実行します。
ブロッキングを避ける
同期I/Oや長時間sleepでイベントループを止めないようにします。
参考(公式ドキュメント)
定期実行
tasks、cron、setIntervalの扱いを分けます。
起動時の重複
再起動やreloadで定期taskが二重に走らないようにします。
失敗時
例外でtaskが止まる場合は管理者ログに出します。
reloadと再起動
Cog reloadやBot再起動で未完了taskを残さない確認です。
reload対象を小さくする
設定、Cog、View、taskを分けて再読み込みします。
復旧手順
本番ではロールバックや再起動手順を決めておきます。
音声Bot・ffmpeg・VC接続
VC参加とVoice State
BotがVCに入れない、入っても再生できない時の確認です。
対象VCを分ける
Guild、Voice Channel、接続済み状態、利用者がいるVC、Botが入るVCを分けます。Connect、Speak、View Channelなど必要権限もチャンネルごとに確認します。
イベントを待つ
音声接続は通常のGatewayとは別のVoice接続を使います。ライブラリがVoice State UpdateとVoice Server Updateをどう扱うか、接続完了前に再生していないかを確認します。
確認ポイント
- 対象guild/channelを固定する
- Connect/Speak権限を見る
- 接続完了ログを出す
- 再生開始を接続完了後にする
参考(公式ドキュメント)
- https://docs.discord.com/developers/topics/voice-connections
- https://docs.discord.com/developers/topics/permissions
再接続と状態管理
切断、移動、再起動後の音声状態を扱います。
状態を持つ
未接続、接続中、再生中、一時停止、切断済み、再接続中を同じbooleanで扱わず、状態として持ちます。
片付けを決める
再起動、disconnect、VC移動、例外発生時に、再生プロセス、キュー、一時ファイル、接続オブジェクトをどう片付けるかを決めます。
確認ポイント
- disconnect時にcleanupする
- 二重接続を防ぐ
- 再接続回数を記録する
参考(公式ドキュメント)
ffmpeg・opus・PATH
ローカルでは鳴るのに本番で鳴らない時の確認です。
依存関係の層を分ける
Discordライブラリ、音声拡張、opus、ffmpeg、OSパッケージ、PATH、CPU/OS差を分けて見ます。node_modulesやvenvを別環境から持ち込むと、native moduleが合わないことがあります。
本番で確認する
ffmpeg -version、build log、runtime log、起動コマンド、PATHを本番環境で確認します。依存関係の値そのものやTokenは公開ログに出しません。
確認ポイント
- ffmpeg -version
- Node/Pythonの版
- 音声パッケージ
- build/runtime log
参考(公式ドキュメント)
外部音源と再生キュー
YouTubeなど外部音源取得とキュー管理をBot本体から分けます。
外部取得を別問題にする
音が出ない時、VC接続の失敗、ffmpegの失敗、外部サービス取得の失敗、URL解析の失敗を同じエラーとして扱わないようにします。
キューを管理する
複数曲、スキップ、停止、再生終了、例外、利用者退出時の挙動を決めます。外部サービスの仕様変更に依存する処理は、失敗時に短く返して管理ログへ詳細を残します。
確認ポイント
- 取得失敗と再生失敗を分ける
- timeoutを設定する
- キューの所有者を決める
- 終了時に一時ファイルを消す
一次情報(公式ドキュメント)
- Railway Docs: Start Command
- Railway Docs: Logs
- Railway Docs: Variables
- Heroku Dev Center: Procfile
- Heroku Dev Center: Logging
- Python asyncio documentation
- discord.py ドキュメント
- Node.js documentation
- Discord Developer Documentation: Voice Connections
- discord.js voice guide