John Wick

StayPresentを使って、スリープせずにオンラインを維持するボットをRailwayにデプロイする方法を解説します。ポートバインディング、ヘルスチェック、セルフping、クラッシュリカバリに対応。

RailwayでStayPresentを使ってPythonボットをスリープさせずに実行する

RailwayはPythonプロジェクトを自動検出し、数分でデプロイできますが、railway python bot(Discordボット、Telegramボット、スクレーパーなど)は、PaaS特有の課題に直面します。プラットフォームはHTTP対応プロセスを期待しますが、ボットのイベントループやゲートウェイ接続は自然にこれを提供しません。このガイドでは、StayPresentを活用してボットをRailwayにデプロイし、オンラインを維持する方法を解説します。

目次

  1. RailwayがPythonアプリを検出・実行する方法
  2. $PORT要件
  3. StayPresentのセットアップ
  4. Railwayダッシュボードでのヘルスチェック
  5. 非アクティブプラン向けのセルフping
  6. クラッシュリカバリ
  7. 完全な動作例
  8. ベストプラクティス
  9. よくあるミス
  10. FAQ
  11. まとめ

RailwayがPythonアプリを検出・実行する方法

Railwayはrequirements.txt(またはpyproject.toml)からPythonプロジェクトを自動検出し、Dockerfile不要でNixpacks経由でコンテナを自動構築します。その後、PORT環境変数でRailwayが割り当てたポートにアプリがバインドすることを期待し、独自のルーティングやヘルスチェックが到達できるようにします。

$PORT要件

これはほぼすべてのモダンなPaaSで見られるパターンです。ハードコードせず、環境変数からPORTを読み取ってください。

import os
import staypresent

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080)),
)

Enter fullscreen mode Exit fullscreen mode

ボットがこのポートに一切バインドしない場合(DiscordやTelegramボットでは正常で想定される動作)、Railwayのヘルスチェック(有効時)は、デプロイをunhealthyと報告します。ボット自体は正常に動作していてもです。

StayPresentのセットアップ

本番環境向けのextraをインストールして、Flaskの開発サーバーではなくWaitressでサーブします。

pip install staypresent[prod]

Enter fullscreen mode Exit fullscreen mode

main.py:

import os
import staypresent

staypresent.web.json({
    "status": "running",
    "service": "my-telegram-bot",
})

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080)),
)

Enter fullscreen mode Exit fullscreen mode

Railwayのスタートコマンドは次のとおりです。

python main.py

Enter fullscreen mode Exit fullscreen mode

Railwayダッシュボードでのヘルスチェック

Railwayのヘルスチェック機能を有効にしている場合、StayPresentの組み込み/healthエンドポイントを指定できます。このエンドポイントは常に{"status": "ok"}を返し、ルートルートでカスタム設定していても影響を受けません。

staypresent.web.json({"status": "running"})
# /health still returns {"status": "ok"} regardless

Enter fullscreen mode Exit fullscreen mode

これにより、プラットフォームレベルのヘルス監視と、/で人間や自前のツール向けに提供するカスタムステータスを分離できます。

非アクティブプラン向けのセルフping

非アクティブによるスリープの有無は、ご利用のRailwayプランや設定によって異なります。必ずRailwayの最新料金・利用規約を確認してください。スリープが適用される場合、staypresent.cron()は自身の公開URLに対してアウトバウンド通信を生成し、アイドル扱いされるのを防ぎます。

import staypresent

staypresent.cron(
    "https://my-app.up.railway.app",
    interval=240,
)

Enter fullscreen mode Exit fullscreen mode

どのプラットフォームでも、実際の公開URLを対象にしてください。0.0.0.0127.0.0.1へのpingはマシン外に出ず、非アクティブ検知に効果がありません。

クラッシュリカバリ

ボットは日常的な理由でクラッシュします。Railwayはコンテナ自体が終了しない限り、コンテナ内のサブプロセスが死んでも自動で再起動しません。StayPresentは内部レイヤーを直接処理します。

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080)),
    restart_on_crash=True,
    max_restarts=5,
    restart_delay=2.0,
    restart_reset_after=60.0,
)

Enter fullscreen mode Exit fullscreen mode

再起動回数が上限に達した場合、StayPresentはボットの元の終了コードでプロセス全体を終了させ、Railwayのデプロイ再起動ポリシーを最終的なセーフティネットとして機能させます。

完全な動作例

import os
import staypresent

staypresent.web.json({"status": "running"})

staypresent.cron("https://my-app.up.railway.app", interval=240)

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080)),
    threads=8,
    restart_on_crash=True,
    max_restarts=5,
)

Enter fullscreen mode Exit fullscreen mode

ベストプラクティス

  • 常にPORTを動的に読み取る — Railwayはデプロイごとに割り当て、環境間で異なる可能性があります。
  • ヘルスチェックを設定する場合は、ルートがカスタムレスポンスを返す場合、/healthを指定する。
  • 実際のトラフィックを受ける本番環境では、必ずprod extraをインストールする。

よくあるミス

  • port=8080をハードコードし、os.getenv("PORT", 8080)を読み取らない — 一部の設定では動作しますが、Railwayの構成によってはサイレントに失敗します。
  • Railwayのスリープ動作がRenderと同じだと仮定する。 ポリシーはプラットフォーム間で異なり、時間とともに変更されます。現在の動作はRailway公式ドキュメントで確認してください。
  • 「Railwayがクラッシュしたデプロイを再起動するから」とクラッシュリカバリをスキップする。 Railwayの再起動ポリシーはコンテナレベルで動作します。コンテナ内でボットサブプロセスがクラッシュするのは別の障害モードで、StayPresentが直接処理します。

FAQ

RailwayにDockerfileは必要ですか?
不要です — RailwayはNixpacks経由でDockerfileなしにPythonプロジェクトを自動検出・ビルドできますが、明示的な制御を希望する場合はDockerfileもサポートされています。

Renderデプロイと同じmain.pyを再利用できますか?
はい — 両プラットフォームが同じ$PORT規約に従うため、同一のエントリポイントが通常そのまま動作します。

Railwayでstaypresent.cron()は必要ですか?
ご利用のプラン/設定で非アクティブによるスリープが適用される場合のみ必要です。利用前にRailwayの最新ドキュメントを確認してください。

まとめ

railway python botをオンラインに保つ方法は、どのモダンなPaaSでも同じです。割り当てられたポートにバインドし、専用のヘルスエンドポイントを公開し、StayPresentにボットプロセス自体を監視させます。セットアップはRailway、Render、Koyeb、Herokuでほぼ同一で、StayPresentがワンタイムの投資になる理由です。

pip install staypresent[prod]

Enter fullscreen mode Exit fullscreen mode