Aiohttp: 分割非同期サーバー実行機能

作成日 2017年07月21日  ·  29コメント  ·  ソース: aio-libs/aiohttp

短編小説

一部のアプリケーションでは、サーバーの実行だけでは不十分であるため、 run_appが必要です。 このrun_app機能を、他の多くのライブラリと同様に、 start()cleanup()の2つの関数に分割できると便利です。 結局のところ、aiohttpは私のアプリの中核ではありません。

アイデアは、メインループを担当し、それがいつどのように実行されるかを制御したいということです。

期待される動作

aiohttpを含める場合は、既存のアプリケーションを変更しないでください。

実際の動作

aiohttpは、Webサーバー部分を実行するために提供されている唯一の関数内でrun_forever()を実行することにより、アプリケーションの中心になります。

再現する手順

  1. asyncioアプリケーションを作成する
  2. aiohttpを使用してWebインターフェイスを含めるようにしてください
  3. aiohttpを中心として同期的に実行されるようにアプリケーションを変更します。
outdated

最も参考になるコメント

私のプロジェクトでは、まったく同じ理由でAsyncServerクラスを実装しました。

このようなもの:

class AsyncServer:
    def __init__(...run_app params..)
    async def start()
    async def shutdown()
    async def wait()
    async def __aenter__()
    async def __aexit__()

正常に動作します )

このようなものは、図書館にあるといいでしょう。

全てのコメント29件

aiohttpはアプリの中心である必要はありません。 run_appヘルパーが何をしているのか見てみましょう: https ://github.com/aio-libs/aiohttp/blob/master/aiohttp/web.py#L412

そのロジックの一部をコードにコピーして、いつでもloop.run_foreverをトリガーできます。 ただし、もちろん、SIGTERM / INTシグナルを処理して、aiohttpを正常にシャットダウンできるようにするなど、いくつかの「プロセス関連」の問題も自分で処理する必要があります。

とにかく、パブリックAPIで別々の起動機能とシャットダウン機能を維持することは理にかなっています。
正直なところ、ソースコードを調べないと、必要なすべての手順を思い出せません。

私のプロジェクトでは、まったく同じ理由でAsyncServerクラスを実装しました。

このようなもの:

class AsyncServer:
    def __init__(...run_app params..)
    async def start()
    async def shutdown()
    async def wait()
    async def __aenter__()
    async def __aexit__()

正常に動作します )

このようなものは、図書館にあるといいでしょう。

これを修正するには、+1を追加する必要があります。 私見、最良の方法は、 aiohttp.web.Application()run()コルーチンメソッドを設定することです。これにより、メインアプリは次のようになります(簡略化)。

async def my_suff():
   ...

def main():
    loop = asyncio.get_event_loop()
    app = web.Application()
    ....
    loop.run_until_complete(
        asyncio.gather(
            app.run("0.0.0.0", 80),
            run_my_stuff(),
        )
    )

さて、それは素敵ではないでしょうか? ;-)

いいえ、別のクラスにする必要があります。
同じアプリを異なるホスト/ポートで実行し、アプリを停止することを検討してください。

その場合、 @alexmnazarenkoAsyncServerのようなものがあれば素晴らしいと思います。 @alexmnazarenko 、あなたのコードはどこかで利用できますか?

@gjcarneiroはい、次のとおりです: https ://github.com/datadvance/pRpc/blob/master/prpc/platform/ws_aiohttp.py

ただし、aiohttp自体に含めるための完全な機能ではありません。 知る必要がないので、UDPソケットのサポートを終了しました。 それでも、単一のasyncioアプリで異なるポートで複数のサーバーを実行できるようにすることは私にとってはうまく機能します。

結局のところ、aiohttpは私のアプリの中核ではありません。

その部分はわかりません。 メインプロセスの存続期間中に、Webサービスを開始および停止しますか? そのユースケースを説明できますか?

@txomon @alexmnazarenkoユースケースを説明できますか? libを提供するpRpcライブラリをチェックしましたが、テスト以外は実際には使用していません。

私の場合、これはボットの一部であり、他の多くのものが同時に実行されていました。 APIを公開したいが、それがサーバーの主な目的ではなかった場合でも、これをメインプロセスとして設定する必要があります。

アイデアは、aiohttpがアプリの中心であると期待されるべきではないということです。

公開しているAPIは、ある時点で公開されませんか? または、APIはプロセスが終了するまで常に実行されていますか?

しかし、それはサーバーの主な目的ではありませんでした

プロジェクトの現在の状態で、APIの有無にかかわらずボットを起動することは可能ですか? それとも、ループからWebサービスに進化したのでしょうか。

アイデアは、aiohttpがアプリの中心であると期待されるべきではないということです。

私はそれを理解しています😁しかし、aiohttpがアプリケーションの中心ではない場合、アプリケーションはしばらくの間APIを公開してから、それを削除するようです。 この特定のユースケースは、私にはあまり意味がありません。

この特定のボットにはいくつかの構成オプションがあり、WebSocketを使用する場合もあれば、http通知をプッシュする場合もあります。 メインプロセスをWebサーバープロセスに結合すると、構成に関係なくWebサーバーを起動する必要があります。

また、ホットプラグインの(再)ロードがあり、新しいエンドポイントに対応するためにWebサーバーを終了して再起動することができます。

どうも! 今ではもっと理にかなっています。 アプリケーションのweb.run_appに正確に何が必要ですか? 信号は自分で処理すると思います。

web.run_appは以下を提供します:

  • SIGTERMおよびSIGINTの処理
  • サーバーの作成と閉鎖
  • 起動、クリーン、シャットダウンのフック

私にとって最善の方法は、実際にこれらの機能をさまざまな機能に分けて、使用するかどうかを決定できるようにすることです。

私の場合、サーバーの作成/閉鎖と起動、クリーン、シャットダウンのフックに違いはありません。

私は内部に精通していませんが、私の場合、次のように使用できる関数を持っています:

  1. この関数を実行/待機してlibを初期化します
  2. この関数がサーバーを起動するのを待つ
  3. この関数がサーバーを停止するのを待つ
  4. この関数を実行/待機して、ライブラリをクリーンアップします

手順2と3をループできる場合(サービスを再開するため)。 ステップ1/4は必要ないかもしれませんが、libcurlなどの他のライブラリのデザインパターンに従うだけです。

@cecton私のユースケースの時点で:

  • 異なるポート上の複数のアプリ+いくつかの非同期初期化/ティアダウン
  • 奇妙なテスト

複数のアプリのユースケースの例:
https://github.com/datadvance/pAgent/blob/master/pagent/__main__.py

ここに、RPC、管理など、すべてにHTTPを使用するプログラムがあります。 RPCアプリと管理アプリには異なるエンドポイントが必要です(管理者は通常ローカルホストのみです)。

いいね! フィードバックをありがとうございました。

信号処理はここでは範囲外だと思うので、フックをトリガーしてフックを作成/削除するstart()およびshutdown() (またはstop() ?)関数が必要です。 @alexmnazarenkohttps://github.com/datadvance/pRpc/blob/master/prpc/platform/ws_aiohttp.pyで行ったようにサーバーをきれいに

私は新しいオブジェクトを紹介することにあまり興味がありません。 @asvetlovクラスApplicationにstartメソッドとstopメソッドを直接追加できると思いますか?

次に、 web.run_appを減らして、シグナルのみを処理し、適切なメソッドを開始します。

あなたはそれがすべてをカバーすると思いますか? 非同期コンテキストとwaitメソッドは役に立たないと思うのでスキップしましたが、完全に間違っている場合は知らせてください。

@asvetlovhttps ://github.com/cecton/aiohttp/commit/3b8a782bc7081944bab49321de07df4ce93c6acbここにサンプル

これは役立つはずです。「待機」やその他の便利な機能は、外部から簡単に実装できます。 私にとっての主なポイントは、run_appシグナル全体をコピーしないようにすることです(バージョン間で変更される可能性があるため)。

それなら完璧ですか? いくつかのテストを行い、期待どおりに機能するかどうかを確認します。

ちなみに「待機」のユースケースは何ですか? クリーンアップフックを使用して同じことを達成できるはずだからです。 また、実装したような非同期コンテキストのユースケースは何でしょうか? たぶんテストで?

「シグナル」とは、アプリケーションの「シグナル」/フックを意味しますか? Unixシグナルではありませんか?

うん、「完璧だよ」:smile:

  1. 待機は重要ではありません。 これは、ローカル変数の煩わしさを軽減するだけで、クリーンアップフックに取って代わります。 しかし、それを処理する方法は複数あるので、「フレームワークに追加するAPIを減らす」ことは、それを削除するのに十分な懸念事項だと思います。
  2. はい、私はフックを意味します。 内部フック実装クラスは実際には「*Signal」と呼ばれているため、私はそれらを「* Signal」と呼んでいます)

コードサンプルのPS「awaitself.cleanup()」は2回呼び出されますか?

はい、それは単なるサンプルでした😫私は自分が考えていたことをアンドリューに示すために本当に速くしました。

新しいメソッドと状態をApplicationに追加するか、サーバーを実行するための新しいクラスを作成する必要があるかわかりません。
ネストされたアプリの場合、これらのメソッドは役に立たないため、呼び出さないでください。

@asvetlov私はそれについて考えていません、そしてそれは良い点です。 私の観点からは、Applicationのロジックはクラス自体で十分にスコープされているようです。 それを別の方法で広めるのは奇妙でした。

新しいクラスは私には問題ありません。 私が書いたように、それはフレームワークからの「不安定な」コピーペーストであるため、コードからフック/ソケット処理を削除したいだけです。

また、私は忘れていました-私の実装には、「解決された」バインドされたエンドポイントを返すという素晴らしいボーナスがありました。 これは、ポート「0」を使用するときに非常に役立ちます。

プルリクエストが必要なようです。
ヒーローはいますか?

@asvetlov営業時間外になりますが、今はしません😀

@asvetlovなので、別のクラスを作成しますか、それともアプリケーションに入れますか?

別のクラスをお勧めします。
アプリケーションはWebサイトを記述し、初期化段階で使用されます。新しいクラスは、単一のホスト/ポートでアプリを実行します。
うーん、結果として、ランナーはon_startup()on_cleanup()のシグナルを呼び出すべきではなく、 on_shutdownだけを呼び出す必要があります。
スタートアップ/クリーンアップは1回だけ呼び出す必要があります。 多分それのために別々の方法が必要です。

@asvetlov多分私は複数のアプリケーションクラスを取り、全体の仕事をするクラスを作ることができますか? すべてが一度呼び出されます。

たぶんそれは良い考えです、APIを見てみましょう。

このスレッドは、閉じられた後、最近のアクティビティがないため、自動的にロックされています。 関連するバグについては、[新しい問題]を開いてください。
この議論で重要なポイントがあると思われる場合は、それらの抜粋をその[新刊]に含めてください。

このページは役に立ちましたか?
0 / 5 - 0 評価