RubyでのプッシュとPub/Sub
Railsでリアルタイム機能を構築することは、ActionCableのようなライブラリではるかに簡単になりました。 AppSignal Academyのこのエピソードでは、リアルタイムの更新に飛び込み、最小限のWebSocketサーバーを構築して、内部でどのように機能するかを確認します。
プッシュするアプリケーションを構築します データ、および Pub / Subを使用します WebSocketを介して 。コードを始める前に、まず、これら3つの概念の意味を説明するために少し時間を費やしましょう。
-
プッシュ 受信者にそのデータのポーリングを行わせる代わりに、データを受信者にプッシュすることを指します。株価、チャットアプリケーション、操作コンソールなどのリアルタイムの更新が必要です。
-
パブ/サブ またはパブリッシュアンドサブスクライブは、1990年代にウォール街でTIBCOによって普及したデータをプッシュするためのインタラクションモデルです。受信者はサブジェクトをサブスクライブし、パブリッシャーがそのサブジェクトにデータをプッシュするのを待ちます。公開されたメッセージをリスナーに一致させるためにワイルドカードパターンマッチングを含めるのが一般的ですが、一部のより単純な実装では、件名にワイルドカードではなく名前付きチャネルのみを使用します。私は初期の頃にTIBCOを始めたので、ワイルドカードパターンマッチングの柔軟性が気に入っています。
-
WebSocket は、データを交換するためのプロトコルです。通常は、Webブラウザとアプリケーションの間で行われます。 HTTP接続がWebSocket接続にアップグレードされ、2つのエンドポイント間でデータを双方向に送信できるようになります。 WebSocketは、アプリケーションからブラウザーにデータをプッシュできます。また、ブラウザのJavaScriptコードからアプリケーションにデータを送信するためのPOSTまたはPUT以外の別のメカニズムも提供します。かなりいいですね
フードの下
WebSocketサーバーの例がどのように機能するかを見てみましょう。クライアントはブラウザから、JavaScriptコードを使用してサーバーへのWebSocket接続を確立しようとします。
var sock = new WebSocket("ws://" + document.URL.split("/")[2] + "/upgrade");
サーバーは、アップグレードが要求されたことを示すインジケーターを含むHTTP要求を受信します。通常、サーバーはアプリケーションにアップグレードするかどうかを決定させます。それがどのように行われるかは、アプリに提供されているAPIによって異なります。 Rackをサポートするサーバーは、ソケットをハイジャックして開発者にすべてのプロトコルの詳細を処理させるオプションを提供します。提案されたPRによれば、アップグレードへの応答で十分です。
アップグレードは、サーバーとクライアント間の一連の交換です。すべてのブラウザと一部のサーバーgemは、これらの詳細を非表示にします。接続が確立されると、WebSocketプロトコルに従ってメッセージを交換できます。
内部の魔法は、エンコード、デコード、およびメッセージ交換プロトコルを処理します。メッセージは、SHA1を使用して暗号化された、末尾にペイロードがあるバイナリの固定幅構造です。 WebSocketプロトコルには、ping / pongハートビート、メッセージ交換の開始と終了など、いくつかのメッセージタイプと交換が含まれています。これは、接続ハイジャックアプローチを使用しないことでサーバーが実行する魔法です。
ダイビング
現在の時刻をすべてのリスニングクライアントに公開するために開始されるクロックスレッドの例を使用します。高速で複雑さを最小限に抑えるため、Agooを使用してサーバーを構築します。
HTMLページに現在の時刻を表示することにより、クライアントとしてJavaScriptから始めます。新しいWebSocket
を作成した後 onopen
ステータスHTML要素を変更するコールバックが設定されます。 onmessage
コールバックはmessage
を更新します HTML要素。コールバックは、パブリッシュ/サブスクライブ交換などの非同期呼び出しを処理する場合の一般的なデザインパターンです。
<!-- websocket.html -->
<html>
<body>
<p id="status">...</p>
<p id="message">... waiting ...</p>
<script type="text/javascript">
var sock = new WebSocket(
"ws://" + document.URL.split("/")[2] + "/upgrade"
);
sock.onopen = function () {
document.getElementById("status").textContent = "connected";
};
sock.onmessage = function (msg) {
document.getElementById("message").textContent = msg.data;
};
</script>
</body>
</html>
クライアントが完成したら、RackAPIを使用したRubyアプリケーションであるサーバーを実装しましょう。 Clock
クラス自体は、/upgrade
上のすべてのHTTPリクエストのハンドラーになります 道。アップグレードのリクエストの場合は、HTTPステータスコード200でSuccessを返します。それ以外の場合は、PageNotFoundの場合は404を返します。 #call
の他の唯一のステップ メソッドはWebSocketハンドラーの割り当てです。
class Clock
def self.call(env)
unless env['rack.upgrade?'].nil?
env['rack.upgrade'] = Clock
[ 200, { }, [ ] ]
else
[ 404, { }, [ ] ]
end
end
end
APIはコールバックに基づいています。サーバーで気になる唯一のコールバックは#on_open
です 「時間」サブジェクトへのサブスクリプションを作成できるようにするコールバック。メッセージは、件名またはトピックによって識別されるチャネルを介して交換されます。 #on_open
Webソケット接続が確立されたときに呼び出されます。
class Clock
# ...
def self.on_open(client)
client.subscribe('time')
end
end
それでは、毎秒時間を公開するスレッドから公開を始めましょう。 Agoo.publish
への呼び出し 「時間」の件名でメッセージを送信すると、すべてのサブスクライバーがメッセージを受信します。サーバーはサブスクリプションと接続を追跡し、HTML要素を更新するJavaScriptクライアントにメッセージを配信します。
require 'agoo'
Thread.new {
loop do
now = Time.now
Agoo.publish('time', "%02d:%02d:%02d" % [now.hour, now.min, now.sec])
sleep(1)
end
}
必要な他のコードは、サーバーを初期化して起動するコードだけです。 Agoo::Server.handle(:GET, '/upgrade', Clock)
の呼び出し /upgrade
でHTTPGETリクエストをリッスンするようにサーバーに指示します URLパスとそれらのリクエストをClock
に渡す クラス。これにより、Rubyの外部でルーティングを実行して、パフォーマンスと柔軟性を向上させることができます。
Agoo::Server.init(6464, '.', thread_count: 0)
Agoo::Server.handle(:GET, '/upgrade', Clock)
Agoo::Server.start
私たちは、ほぼ、そこにいる。このコマンドでサーバーを実行します。
$ ruby pubsub.rb
サーバーがポート6464で実行され、リッスンしていることを示す、次のようなログエントリが表示されます。
I 2018/08/14 19:49:45.170618000 INFO: Agoo 2.5.0 with pid 40366 is listening on https://:6464.
機能しているかどうかを確認する時間
http:// localhost:6464/websocket.htmlを開きましょう。接続が確立されたときの最初のちらつきの後、接続ステータスと時刻が表示されます。時計が刻むにつれて、時間は1秒ごとに増加します。
connected
19:50:12
Webアプリケーションのパブリッシュおよびサブスクライブを作成しておめでとうございます;-)
今日のエピソードでは、WebSocketの使用について説明しました。サーバーサイドイベント(SSE)には、同じことを行う別のオプションがあり、完全なソースコードの例にSSEが含まれています。詳細については、使用したAgooサーバーまたはIodineWebSocketサーバーをご覧ください。
ご質問やご意見がございましたら、お気軽に@AppSignalまでご連絡ください。
-
LoggerとLogrageを使用してRubyにログインする
Rubyでのログの操作 ロギングは、アプリケーションが通常対処する主要なタスクの1つです。ログは、たとえば、必要なときに使用されます アプリ内で何が起こっているかを確認します それらを監視する、または 特定のデータの指標を収集します。 新しいプログラミング言語を学ぶとき、情報を記録するための最初の明白な選択は、ネイティブメカニズムです。通常、それは簡単で、文書化されており、コミュニティ全体に広く行き渡っています。 ログデータは、使用している会社、ビジネス、アプリケーションの種類によって大きく異なります。したがって、あなたとあなたのチームが選択したロギングソリューションがその全体的な使
-
Redis Jedis pubsub-jedisライブラリを使用してpub/subシステムを実装する方法
このチュートリアルでは、Jedisライブラリを使用してredispubサブシステムを実装する方法について学習します。 ジェダイライブラリ Jedisは、redisデータストア用のJavaクライアントライブラリです。小さくて非常に使いやすく、redis 2.8.x、3.x.x以降のデータストアと完全に互換性があります。 jedisライブラリの詳細についてはこちらをご覧ください。 Redis Pub / Sub System Redisは、パブリッシュ/サブスクライブメッセージングパラダイムを実装します。このメッセージングパラダイムによれば、メッセージの送信者(発行者)は、メッセージ