簡體   English   中英

確保使用 Flask-socketio、redis 發送套接字消息

[英]Ensuring socket messages were sent using flask-socketio, redis

我有一個在多個 Pod 上運行的 Flask-socketio 服務器,使用 redis 作為消息隊列。 我想確保來自外部進程的發出 100% 的時間到達目的地,或者知道它們何時失敗。

當進程 A 向連接到進程 B 的套接字發出事件時,該事件通過消息隊列到達進程 B,到達客戶端。 有什么辦法可以攔截進程 B 上的傳出發射? 理想情況下,我會在幾秒鍾后使用工作人員檢查消息是否到達客戶端(通過客戶端發出的確認事件),否則將再次發出。

此代碼在進程 A 上運行:

@app.route('/ex')
def ex_route():
    socketio.emit('external', {'text': f'sender: {socket.gethostname()}, welcome!'}, room='some_room')
    return jsonify(f'sending message to room "some_room" from {socket.gethostname()}')

這是進程A的輸出

INFO:socketio.server:emitting event "external" to some_room [/]
INFO:geventwebsocket.handler:127.0.0.1 - - [2019-01-11 13:33:44] "GET /ex HTTP/1.1" 200 177 0.003196

這是進程B的輸出

INFO:engineio.server:9aab2215a0da4816a45e3fdc1e449fce: Sending packet MESSAGE data 2["external",{"text":"sender: *******, welcome!"}]

不幸的是,目前沒有機制可以執行您的要求。

我認為你基本上有兩種方法來解決這個問題:

  1. 始終從主服務器運行您的發射。 如果您需要從輔助進程發出,請使用 IPC 機制通知服務器,以便它可以代表它運行發出。 現在您可以使用回調。

  2. 忽略回調,而是讓客戶端通過發送回服務器來確認收到事件。

順便說一下,為輔助進程添加回調支持應該不是非常困難。 我自己從來不需要那個功能,而你是第一個提出這個問題的人。 也許我應該在某個時候研究一下。

編輯:經過一番思考,我想出了第三個選項:

您可以將外部進程作為客戶端連接到服務器,而不是使用“僅發送”選項。 如果這個進程是一個客戶端,它可以向服務器發出一個事件,服務器又可以中繼到外部客戶端。 當客戶端回復服務器時,服務器可以再次將響應中繼到外部進程,該進程不是另一個客戶端並且具有完整的發送和接收能力。

使用 IPC 不是很健壯,特別是在服務器收到大量請求的情況下,可能會出現您收到消息但不重新翻譯它的問題,這很重要。

使用 celery 或 zmq 或 redis 本身進行互連。 最自然的是使用如 Miguel 提到的 socketio 本身,因為它已經在等待請求,擁有環境並且可以隨時發出。

我在線程上使用了greenlet hack - 其中greenlet比線程更輕並且在相同的環境中運行,允許它在主線程以非阻塞模式等待套接字時發送消息。 基本上,您編寫一個線程,然后通過monkeypatching 將eventlet 或gevent 應用於整個代碼,並且該線程成為greenlet - 一個中間函數調用。 你把它睡了,這樣它就不會占用所有資源,你有你的發件人,因為 greenlets 很容易共享環境,它們不受 io 的約束,只是 cpu(這與 Python 中的線程相同,但 greenlets 由於根本沒有操作系統級別的上下文更改)。

但是一旦 CPU 負載增加,我就切換到客戶端/服務器。 注入 IPC 需要從頭開始進行大量重寫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM