5

メインの Django アプリケーション プロセスで Celery タスクの結果にアクセスするにはどうすればよいですか? または、別のプロセスから既存のソケット接続に公開するにはどうすればよいですか?

ユーザーがスコアを受け取るアプリケーションがあります。スコアが記録されると、計算が行われ (目標への進捗状況など)、それらの計算に基づいて、関心のあるユーザーに通知が送信されます。計算には 30 秒以上かかる場合があるため、UI の遅延を避けるために、これらの操作は、Score モデルの post_save シグナルによって呼び出される Celery タスクを介してバックグラウンド プロセスで実行されます。

私の Nofication モデルの post_save シグナルが、サブスクライブしたクライアントにメッセージを発行するのが理想的です (私は gevent-socketio のラッパーである django-socketio を使用しています)。これは簡単に思えます...

  1. スコアを作成する
  2. バックグラウンド プロセスで新しい Score インスタンスに対していくつかの計算を行う
  3. これらの計算に基づいて、通知を作成します
  4. 通知の保存時に、インスタンスを取得し、ソケット接続を介してサブスクライブしたクライアントに公開します

ただし、次のことを試した後、これが可能かどうかわかりません。

  • gevent の SocketIOServer インスタンスをタスクによって呼び出されたコールバック メソッドに渡しますが、これには渡されたオブジェクトをピクルする必要があり、これは不可能です。

  • ソケットの session_id (Django の session_id とは異なります) を memchache に格納し、それを Celery タスク プロセスで取得します。

  • Redis pubsub を使用するため、バックグラウンド プロセスで作成されたモデルの post_save シグナルによって呼び出されるメソッドは、単純に Redis チャネルに発行できますが、(ソケット接続にアクセスできる) メイン アプリケーション プロセスでチャット チャネルをリッスンすると、アプリケーションの残りの部分がブロックされます。

  • また、Redis クライアントごとに新しいスレッドを生成しようとしました。これは、ソケット サブスクライバーごとに作成されます。私が知る限り、これには新しいgevent.greenlets.Greenletを生成する必要があり、geventは複数のスレッドで使用できません

確かにこれは解決済みの問題です。私は何が欠けていますか?

4

1 に答える 1

0

あなたはすでにdjango-socketioを持っています.redisでpub/subを書くのは残念です:)

クライアント側:

var socket = new io.Socket();
socket.connect();
socket.on('connect', function() {
    socket.subscribe({{ score_update_channel }});
});

サーバ側:

from django_socketio import broadcast_channel
def user_score_update(user):
    return 'score_updates_user_%s' % user.pk

channel = user_score_update(user)
broadcast_channel(score_result_data, channel)

django-socketio プロセスでブロードキャストを実行する必要があります。別のプロセス (セロリ ワーカー) から実行すると機能しません (チャネルは django-socketio プロセスによってメモリ内で参照されます)。ビューでラップすることでこれを解決でき、タスクが完了するとセロリが呼び出します(実際のhttpリクエストを作成します)。

于 2013-04-03T06:42:34.447 に答える