一、总体设计思路(先看这个)
我们把 tdeinge REST API 客户端 设计成 4 层:
TDEngineClient
├─ HTTP 会话层(requests.Session)
├─ 重试机制(Retry + Backoff)
├─ 错误处理(网络 / 超时 / 业务错误)
└─ 业务接口(query / read / health)
📌 目标:
调用方只关心:
client.query(sql)是否成功
二、核心技术选型
| 功能 | 技术 |
|---|---|
| HTTP 客户端 | requests.Session |
| 重试 | urllib3.Retry |
| 超时 | connect / read timeout |
| 日志 | logging |
| 线程安全 | Session 级别 |
三、tdeinge REST API 客户端封装(完整代码)
1️⃣ tdeinge_client.py
python
import requests
import logging
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
logger = logging.getLogger(__name__)
class TDEngineClient:
def __init__(
self,
base_url: str,
username: str,
password: str,
timeout: int = 5,
max_retries: int = 3
):
"""
:param base_url: http://localhost:6041
:param username: root
:param password: taosdata
:param timeout: 请求超时时间(秒)
:param max_retries: 最大重试次数
"""
self.base_url = base_url.rstrip("/")
self.timeout = timeout
self.session = requests.Session()
self.session.auth = (username, password)
retry_strategy = Retry(
total=max_retries,
backoff_factor=0.5, # 0.5s, 1s, 2s
status_forcelist=[500, 502, 503, 504],
allowed_methods=["GET", "POST"],
raise_on_status=False
)
adapter = HTTPAdapter(max_retries=retry_strategy)
self.session.mount("http://", adapter)
self.session.mount("https://", adapter)
# =============================
# 基础请求方法
# =============================
def _post(self, path: str, payload: dict):
url = f"{self.base_url}{path}"
try:
resp = self.session.post(
url,
json=payload,
timeout=self.timeout
)
resp.raise_for_status()
return resp.json()
except requests.exceptions.Timeout:
logger.error("TDEngine request timeout")
raise
except requests.exceptions.ConnectionError:
logger.error("TDEngine connection error")
raise
except requests.exceptions.HTTPError as e:
logger.error(f"TDEngine HTTP error: {e}")
raise
except Exception as e:
logger.exception("Unexpected TDEngine error")
raise
# =============================
# 业务接口
# =============================
def query(self, sql: str):
"""
执行 SQL 查询
"""
result = self._post(
path="/rest/sql",
payload={"sql": sql}
)
# TDEngine 业务错误判断
if result.get("status") != "succ":
raise RuntimeError(
f"TDEngine query failed: {result}"
)
return result["data"]
def ping(self) -> bool:
"""
健康检查
"""
try:
self.query("select server_version()")
return True
except Exception:
return False
四、使用示例(非常干净)
python
client = TDEngineClient(
base_url="http://localhost:6041",
username="root",
password="taosdata"
)
rows = client.query("""
SELECT ts, temperature
FROM sensor_data
LIMIT 10
""")
返回数据示例:
python
[
["2025-01-01 10:00:00", 23.4],
["2025-01-01 10:01:00", 23.6]
]
五、和 FastAPI 结合(推荐)
1️⃣ 单例注入(避免重复建连接)
python
# deps.py
from .tdeinge_client import TDEngineClient
td_client = TDEngineClient(
base_url="http://localhost:6041",
username="root",
password="taosdata"
)
def get_td_client():
return td_client
2️⃣ FastAPI 路由中使用
python
from fastapi import APIRouter, Depends
from deps import get_td_client
router = APIRouter()
@router.get("/cop")
def read_cop(client=Depends(get_td_client)):
data = client.query("""
SELECT AVG(cop)
FROM cop_table
WHERE ts > now - 1h
""")
return {"value": data[0][0]}
六、稳定性保障点(这是重点)
✅ 1️⃣ 自动重试(网络抖动)
- 连接失败
- 500 / 503
- 指数退避
✅ 2️⃣ 超时控制
python
timeout=5
不会卡死 FastAPI worker
✅ 3️⃣ Session 复用
- TCP 连接池
- 性能稳定
✅ 4️⃣ 明确的异常边界
| 异常 | 含义 |
|---|---|
| Timeout | 网络慢 |
| ConnectionError | TD 未启动 |
| HTTPError | 网关异常 |
| RuntimeError | SQL / 业务错误 |
七、增强版(生产环境强烈推荐)
1️⃣ 熔断(连续失败直接失败)
text
失败 N 次 → 短时间拒绝请求
可用:
pybreaker- 自己用计数器
2️⃣ 读写分离
python
query_read()
query_write()
3️⃣ SQL 注入保护
python
assert "drop" not in sql.lower()
4️⃣ 统一监控
- 请求耗时
- 错误率
- 重试次数
八、你现在已经具备的能力
✅ 稳定读取 tdeinge REST API
✅ 自动重试 & 超时
✅ 可直接用于 FastAPI
✅ 易维护、易测试
✅ 可扩展到 WebSocket / 批量查询