开发机迁移
This commit is contained in:
@@ -31,6 +31,31 @@ from app.config import (
|
||||
ETL_DB_USER,
|
||||
)
|
||||
|
||||
# TCP keepalive 参数:防止长期运行的后台服务连接被网络设备/PostgreSQL 回收
|
||||
_KEEPALIVE_KWARGS = {
|
||||
"keepalives": 1,
|
||||
"keepalives_idle": 60, # 空闲 60 秒后开始探测
|
||||
"keepalives_interval": 10, # 每 10 秒探测一次
|
||||
"keepalives_count": 3, # 连续 3 次失败判定断开
|
||||
}
|
||||
|
||||
# 连接重试参数:应对 PostgreSQL 瞬时不可用(Tailscale 网络抖动等)
|
||||
_CONNECT_MAX_RETRIES = 3
|
||||
_CONNECT_RETRY_DELAY = 1.0 # 秒
|
||||
|
||||
|
||||
def _connect_with_retry(connect_fn, max_retries=_CONNECT_MAX_RETRIES):
|
||||
"""带重试的数据库连接,应对服务端瞬时拒绝连接。"""
|
||||
last_exc = None
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return connect_fn()
|
||||
except psycopg2.OperationalError as e:
|
||||
last_exc = e
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(_CONNECT_RETRY_DELAY * (attempt + 1))
|
||||
raise last_exc
|
||||
|
||||
|
||||
def get_connection() -> PgConnection:
|
||||
"""
|
||||
@@ -49,13 +74,14 @@ def get_connection() -> PgConnection:
|
||||
|
||||
start = time.perf_counter() if should_trace else 0.0
|
||||
|
||||
conn = psycopg2.connect(
|
||||
conn = _connect_with_retry(lambda: psycopg2.connect(
|
||||
host=DB_HOST,
|
||||
port=DB_PORT,
|
||||
user=DB_USER,
|
||||
password=DB_PASSWORD,
|
||||
dbname=APP_DB_NAME,
|
||||
)
|
||||
**_KEEPALIVE_KWARGS,
|
||||
))
|
||||
|
||||
if should_trace:
|
||||
from datetime import datetime
|
||||
@@ -86,13 +112,14 @@ def get_etl_global_readonly_connection() -> PgConnection:
|
||||
|
||||
用于系统管理后台等不需要门店隔离的场景(如 ETL 状态监控)。
|
||||
"""
|
||||
conn = psycopg2.connect(
|
||||
conn = _connect_with_retry(lambda: psycopg2.connect(
|
||||
host=ETL_DB_HOST,
|
||||
port=ETL_DB_PORT,
|
||||
user=ETL_DB_USER,
|
||||
password=ETL_DB_PASSWORD,
|
||||
dbname=ETL_DB_NAME,
|
||||
)
|
||||
**_KEEPALIVE_KWARGS,
|
||||
))
|
||||
try:
|
||||
conn.autocommit = False
|
||||
with conn.cursor() as cur:
|
||||
@@ -121,13 +148,14 @@ def get_etl_readonly_connection(site_id: int | str) -> PgConnection:
|
||||
finally:
|
||||
conn.close()
|
||||
"""
|
||||
conn = psycopg2.connect(
|
||||
conn = _connect_with_retry(lambda: psycopg2.connect(
|
||||
host=ETL_DB_HOST,
|
||||
port=ETL_DB_PORT,
|
||||
user=ETL_DB_USER,
|
||||
password=ETL_DB_PASSWORD,
|
||||
dbname=ETL_DB_NAME,
|
||||
)
|
||||
**_KEEPALIVE_KWARGS,
|
||||
))
|
||||
try:
|
||||
conn.autocommit = False
|
||||
with conn.cursor() as cur:
|
||||
@@ -142,3 +170,23 @@ def get_etl_readonly_connection(site_id: int | str) -> PgConnection:
|
||||
conn.close()
|
||||
raise
|
||||
return conn
|
||||
|
||||
|
||||
def get_etl_write_connection() -> PgConnection:
|
||||
"""
|
||||
获取 ETL 数据库(etl_feiqiu)的可写连接。
|
||||
|
||||
仅用于后端需要回写 ETL 汇总表的场景(如 task_generator 回写关系指数统计)。
|
||||
不设置 RLS 隔离,调用方需在 SQL 中显式指定 site_id。
|
||||
调用方负责关闭连接。
|
||||
"""
|
||||
conn = _connect_with_retry(lambda: psycopg2.connect(
|
||||
host=ETL_DB_HOST,
|
||||
port=ETL_DB_PORT,
|
||||
user=ETL_DB_USER,
|
||||
password=ETL_DB_PASSWORD,
|
||||
dbname=ETL_DB_NAME,
|
||||
**_KEEPALIVE_KWARGS,
|
||||
))
|
||||
conn.autocommit = False
|
||||
return conn
|
||||
|
||||
Reference in New Issue
Block a user