feat:
--Added new Link and register API
This commit is contained in:
1 parent
a92d68fa35
commit
ce55d6f591
3 files changed
+272
-37
No files matched your search
+41
-1
@@ -244,4 +244,44 @@ psql "postgresql://postgres_exporter:postgres@172.16.10.178:5444/postgres"
|
|||||||
|=============================|
|
|=============================|
|
||||||
|ENDPONT TO DETECT A DEAD LOCK|
|
|ENDPONT TO DETECT A DEAD LOCK|
|
||||||
|=============================|
|
|=============================|
|
||||||
http://172.16.10.178:9188/metrics | grep -i deadlock
|
http://172.16.10.178:9188/metrics | grep -i deadlock
|
||||||
|
|
||||||
|
|
||||||
|
|========================|
|
||||||
|
|FEATURES COMPLETED TODAY|
|
||||||
|
|========================|
|
||||||
|
|
||||||
|
| Requirement | `postgres_exporter` | What you need |
|
||||||
|
| ----------------------- | ------------------: | --------------------------------- |
|
||||||
|
| Connections | ✅ | postgres_exporter |
|
||||||
|
| Transactions | ✅ | postgres_exporter |
|
||||||
|
| Locks | ✅/⚠️ | PostgreSQL metrics/custom query |
|
||||||
|
| Blocking sessions | ⚠️ | Custom PostgreSQL query |
|
||||||
|
| Deadlocks | ✅ | postgres_exporter |
|
||||||
|
| Long-running queries | ⚠️ | `pg_stat_activity` / custom query |
|
||||||
|
| WAL | ✅ | postgres_exporter |
|
||||||
|
| Database health | ✅ | postgres_exporter + Prometheus |
|
||||||
|
| PostgreSQL CPU usage | ❌ | cAdvisor / process monitoring |
|
||||||
|
| PostgreSQL memory usage | ❌ | cAdvisor / process monitoring |
|
||||||
|
| Storage/disk usage | ❌ | node_exporter / cAdvisor |
|
||||||
|
| Network usage | ❌ | node_exporter / cAdvisor |
|
||||||
|
|
||||||
|
|
||||||
|
|==================|
|
||||||
|
| Whats This for? |
|
||||||
|
|==================|
|
||||||
|
|
||||||
|
postgres=# SELECT *
|
||||||
|
FROM spock.replication_set_table;
|
||||||
|
set_id | set_reloid | set_att_list | set_row_filter
|
||||||
|
-----------+------------------+--------------+----------------
|
||||||
|
590430464 | ddl_test | |
|
||||||
|
590430464 | test_replication | |
|
||||||
|
590430464 | lock_test | |
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
postgres=#
|
||||||
|
|
||||||
|
|
||||||
|
!!!!!!!!!WHEN TESTING NEW NODES OR REFRESHING THE NODES!!!!!!!!!
|
||||||
|
SET spock.enable_ddl_replication = off;
|
||||||
@@ -1,47 +1,229 @@
|
|||||||
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from pydantic import BaseModel
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
# ===== TEST DATA =====
|
app = FastAPI()
|
||||||
# id = 600
|
|
||||||
source_node = "node1"
|
|
||||||
message = "from python with love "
|
|
||||||
|
|
||||||
conn = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
conn = psycopg2.connect(
|
|
||||||
host="172.16.10.123",
|
|
||||||
port=5444,
|
|
||||||
database="postgres",
|
|
||||||
user="postgres",
|
|
||||||
password="postgres"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
cursor = conn.cursor()
|
class RegisterNodeRequest(BaseModel):
|
||||||
|
node_name: str
|
||||||
|
host: str
|
||||||
|
port: int = 5444
|
||||||
|
dbname: str = "postgres"
|
||||||
|
user: str = "postgres"
|
||||||
|
password: str
|
||||||
|
|
||||||
cursor.execute("""
|
|
||||||
INSERT INTO test_replication (source_node, message)
|
|
||||||
VALUES (%s, %s)
|
|
||||||
RETURNING id
|
|
||||||
""", (source_node, message))
|
|
||||||
|
|
||||||
# Get the ID generated by PostgreSQL
|
class LinkNodeRequest(BaseModel):
|
||||||
generated_id = cursor.fetchone()[0]
|
subscription_name: str
|
||||||
|
|
||||||
conn.commit()
|
# The node where sub_create() must run
|
||||||
|
subscriber_host: str
|
||||||
|
subscriber_port: int = 5444
|
||||||
|
|
||||||
print("LOCAL COMMIT: SUCCESS")
|
# The provider node
|
||||||
print("Generated ID:", generated_id)
|
provider_host: str
|
||||||
print("Source:", source_node)
|
provider_port: int = 5444
|
||||||
print("Message:", message)
|
|
||||||
|
|
||||||
except Exception as e:
|
dbname: str = "postgres"
|
||||||
if conn:
|
user: str = "postgres"
|
||||||
conn.rollback()
|
password: str
|
||||||
|
|
||||||
print("LOCAL COMMIT: FAILED")
|
|
||||||
print("Error:", e)
|
|
||||||
|
|
||||||
finally:
|
#POST /register-node
|
||||||
if conn:
|
# {
|
||||||
conn.close()
|
# "node_name": "node2",
|
||||||
|
# "host": "172.16.10.110",
|
||||||
|
# "port": 5444,
|
||||||
|
# "dbname": "postgres",
|
||||||
|
# "user": "postgres",
|
||||||
|
# "password": "postgres"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# postgres=# SELECT spock.node_add_interface(
|
||||||
|
# 'node2',
|
||||||
|
# 'node2_external',
|
||||||
|
# 'host=172.16.10.110 port=5444 dbname=postgres user=postgres password=postgres'
|
||||||
|
# );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/register-node")
|
||||||
|
def register_node(data: RegisterNodeRequest):
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
cur = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect to the node we want to register
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=data.host,
|
||||||
|
port=data.port,
|
||||||
|
dbname=data.dbname,
|
||||||
|
user=data.user,
|
||||||
|
password=data.password
|
||||||
|
)
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# 1. Create Spock extension
|
||||||
|
cur.execute("""
|
||||||
|
CREATE EXTENSION IF NOT EXISTS spock;
|
||||||
|
""")
|
||||||
|
|
||||||
|
# 2. Check Spock version
|
||||||
|
cur.execute("""
|
||||||
|
SELECT extname, extversion
|
||||||
|
FROM pg_extension
|
||||||
|
WHERE extname = 'spock';
|
||||||
|
""")
|
||||||
|
|
||||||
|
spock = cur.fetchone()
|
||||||
|
|
||||||
|
# 3. Build node DSN
|
||||||
|
dsn = (
|
||||||
|
f"host={data.host} "
|
||||||
|
f"port={data.port} "
|
||||||
|
f"dbname={data.dbname} "
|
||||||
|
f"user={data.user} "
|
||||||
|
f"password={data.password}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 4. Create Spock node
|
||||||
|
cur.execute("""
|
||||||
|
SELECT spock.node_create(
|
||||||
|
node_name := %s,
|
||||||
|
dsn := %s
|
||||||
|
);
|
||||||
|
""", (
|
||||||
|
data.node_name,
|
||||||
|
dsn
|
||||||
|
))
|
||||||
|
|
||||||
|
node_id = cur.fetchone()[0]
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# 5. Show registered nodes
|
||||||
|
cur.execute("""
|
||||||
|
SELECT node_id, node_name
|
||||||
|
FROM spock.node;
|
||||||
|
""")
|
||||||
|
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
nodes = [
|
||||||
|
{
|
||||||
|
"node_id": row[0],
|
||||||
|
"node_name": row[1]
|
||||||
|
}
|
||||||
|
for row in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": "Node registered",
|
||||||
|
"node_id": node_id,
|
||||||
|
"spock_version": spock[1],
|
||||||
|
"nodes": nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if conn:
|
||||||
|
conn.rollback()
|
||||||
|
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if cur:
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
if conn:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# {
|
||||||
|
# "subscription_name": "node2_from_node1",
|
||||||
|
# "subscriber_host": "172.16.10.110",
|
||||||
|
# "subscriber_port": 5444,
|
||||||
|
# "provider_host": "172.16.10.123",
|
||||||
|
# "provider_port": 5444,
|
||||||
|
# "dbname": "postgres",
|
||||||
|
# "user": "postgres",
|
||||||
|
# "password": "postgres"
|
||||||
|
# }
|
||||||
|
@app.post("/link-nodes")
|
||||||
|
def link_nodes(data: LinkNodeRequest):
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
cur = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# IMPORTANT:
|
||||||
|
# Connect to the subscriber node.
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=data.subscriber_host,
|
||||||
|
port=data.subscriber_port,
|
||||||
|
dbname=data.dbname,
|
||||||
|
user=data.user,
|
||||||
|
password=data.password
|
||||||
|
)
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# Provider DSN
|
||||||
|
provider_dsn = (
|
||||||
|
f"host={data.provider_host} "
|
||||||
|
f"port={data.provider_port} "
|
||||||
|
f"dbname={data.dbname} "
|
||||||
|
f"user={data.user} "
|
||||||
|
f"password={data.password}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create subscription
|
||||||
|
# Create subscription
|
||||||
|
cur.execute("""
|
||||||
|
SELECT spock.sub_create(
|
||||||
|
subscription_name := %s,
|
||||||
|
provider_dsn := %s,
|
||||||
|
synchronize_structure := true,
|
||||||
|
synchronize_data := true
|
||||||
|
);
|
||||||
|
""", (
|
||||||
|
data.subscription_name,
|
||||||
|
provider_dsn
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
subscription_id = cur.fetchone()[0]
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": "Nodes linked successfully",
|
||||||
|
"subscription_id": subscription_id,
|
||||||
|
"subscription_name": data.subscription_name,
|
||||||
|
"subscriber": data.subscriber_host,
|
||||||
|
"provider": data.provider_host
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if conn:
|
||||||
|
conn.rollback()
|
||||||
|
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if cur:
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
if conn:
|
||||||
|
conn.close()
|
||||||
@@ -1,3 +1,16 @@
|
|||||||
|
annotated-doc==0.0.5
|
||||||
|
annotated-types==0.8.0
|
||||||
|
anyio==4.14.2
|
||||||
|
click==8.5.0
|
||||||
|
fastapi==0.141.1
|
||||||
|
h11==0.16.0
|
||||||
|
idna==3.19
|
||||||
psycopg==3.3.4
|
psycopg==3.3.4
|
||||||
psycopg-binary==3.3.4
|
psycopg-binary==3.3.4
|
||||||
|
psycopg2-binary==2.9.12
|
||||||
|
pydantic==2.13.5
|
||||||
|
pydantic_core==2.46.5
|
||||||
|
starlette==1.6.0
|
||||||
|
typing-inspection==0.4.4
|
||||||
typing_extensions==4.16.0
|
typing_extensions==4.16.0
|
||||||
|
uvicorn==0.52.4
|
||||||
Reference in new issue
Block a user