feat:
--Added async websocket API to check connection status
This commit is contained in:
1 parent
8690f1ba27
commit
7d66c24430
1 file changed
+147
-16
@@ -1,12 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from fastapi import FastAPI,Depends, Header, HTTPException, status
|
from fastapi import FastAPI,Depends, Header, HTTPException, status, WebSocket, WebSocketDisconnect
|
||||||
import psycopg2
|
import psycopg2
|
||||||
from jwt import ExpiredSignatureError, InvalidTokenError
|
from jwt import ExpiredSignatureError, InvalidTokenError
|
||||||
import jwt
|
import jwt
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from psycopg2.extras import RealDictCursor
|
||||||
|
import asyncio
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
@@ -90,19 +91,6 @@ def root():
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
host = os.getenv("HOST", "127.0.0.1")
|
|
||||||
port = int(os.getenv("PORT", 9000))
|
|
||||||
|
|
||||||
uvicorn.run(
|
|
||||||
"main:app",
|
|
||||||
host=host,
|
|
||||||
port=port,
|
|
||||||
reload=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#{
|
#{
|
||||||
# "host": "172.16.10.178",
|
# "host": "172.16.10.178",
|
||||||
# "node_name = "node3",
|
# "node_name = "node3",
|
||||||
@@ -143,4 +131,147 @@ def node_status(data: NodeStatusRequest,token_data=Depends(verify_token)):
|
|||||||
"online": False,
|
"online": False,
|
||||||
"status": "offline",
|
"status": "offline",
|
||||||
"error": str(e)
|
"error": str(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
latest_replication_health = None
|
||||||
|
monitor_task = None
|
||||||
|
def get_replication_health(data: NodeStatusRequest):
|
||||||
|
|
||||||
|
db_config = {
|
||||||
|
"host": data.host,
|
||||||
|
"port": data.port,
|
||||||
|
"dbname": data.dbname,
|
||||||
|
"user": data.user,
|
||||||
|
"password": data.password,
|
||||||
|
"connect_timeout": 2,
|
||||||
|
"options": "-c statement_timeout=2000"
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(**db_config)
|
||||||
|
|
||||||
|
cur = conn.cursor(cursor_factory=RealDictCursor)
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT
|
||||||
|
subscription_name,
|
||||||
|
status,
|
||||||
|
provider_node
|
||||||
|
FROM spock.sub_show_status();
|
||||||
|
""")
|
||||||
|
|
||||||
|
subscriptions = cur.fetchall()
|
||||||
|
|
||||||
|
healthy = all(
|
||||||
|
sub["status"] == "replicating"
|
||||||
|
for sub in subscriptions
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"node": data.node_name,
|
||||||
|
"connection_healthy": healthy,
|
||||||
|
"subscriptions": subscriptions
|
||||||
|
}
|
||||||
|
except psycopg2.errors.QueryCanceled:
|
||||||
|
|
||||||
|
print("Query cancelled because it exceeded 2 seconds")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "timeout",
|
||||||
|
"message": "PostgreSQL query exceeded timelimit and was cancelled"
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
|
||||||
|
return {
|
||||||
|
"node": data.node_name,
|
||||||
|
"connection_healthy": False,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if conn:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
@app.websocket("/ws/node/replication-health")
|
||||||
|
async def replication_monitor(websocket: WebSocket):
|
||||||
|
await websocket.accept()
|
||||||
|
try:
|
||||||
|
raw_data = await websocket.receive_json()
|
||||||
|
data = NodeStatusRequest(**raw_data)
|
||||||
|
global latest_replication_health
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
result = await asyncio.wait_for(
|
||||||
|
asyncio.to_thread(
|
||||||
|
get_replication_health,
|
||||||
|
data
|
||||||
|
),
|
||||||
|
timeout=6
|
||||||
|
)
|
||||||
|
|
||||||
|
latest_replication_health = result
|
||||||
|
|
||||||
|
print("Replication health:")
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
|
||||||
|
latest_replication_health = {
|
||||||
|
"node": data.node_name,
|
||||||
|
"connection_healthy": False,
|
||||||
|
"status": "timeout",
|
||||||
|
"message": "PostgreSQL operation exceeded maximum time"
|
||||||
|
}
|
||||||
|
|
||||||
|
print(latest_replication_health)
|
||||||
|
|
||||||
|
await websocket.send_json(
|
||||||
|
latest_replication_health
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait 2 seconds before checking again
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
except WebSocketDisconnect:
|
||||||
|
|
||||||
|
print("WebSocket client disconnected")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
host = os.getenv("HOST", "127.0.0.1")
|
||||||
|
port = int(os.getenv("PORT", 9000))
|
||||||
|
|
||||||
|
uvicorn.run(
|
||||||
|
"main:app",
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
reload=False
|
||||||
|
)
|
||||||
|
|
||||||
Reference in new issue
Block a user