修复 prefect中psql报错
This commit is contained in:
+17
-36
@@ -2,10 +2,10 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import csv
|
import csv
|
||||||
import io
|
import io
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
|
||||||
from .settings import AppConfig
|
from .settings import AppConfig
|
||||||
from .specs import BrandSyncTarget
|
from .specs import BrandSyncTarget
|
||||||
from .sql import DEFAULT_SYNC_TARGET, POSTGRES_QUERY, build_postgres_query
|
from .sql import DEFAULT_SYNC_TARGET, POSTGRES_QUERY, build_postgres_query
|
||||||
@@ -27,40 +27,21 @@ def query_postgres(
|
|||||||
warehouse_keys=active_warehouse_keys,
|
warehouse_keys=active_warehouse_keys,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
env = os.environ.copy()
|
output = io.StringIO()
|
||||||
env["PGPASSWORD"] = config.analytics_db_password
|
|
||||||
command = [
|
|
||||||
"/usr/local/bin/psql",
|
|
||||||
"-h",
|
|
||||||
config.analytics_db_host,
|
|
||||||
"-p",
|
|
||||||
config.analytics_db_port,
|
|
||||||
"-U",
|
|
||||||
config.analytics_db_user,
|
|
||||||
"-d",
|
|
||||||
config.analytics_db_name,
|
|
||||||
"-v",
|
|
||||||
"ON_ERROR_STOP=1",
|
|
||||||
"-c",
|
|
||||||
"SET TIME ZONE 'Asia/Shanghai';",
|
|
||||||
"-c",
|
|
||||||
f"COPY ({query}) TO STDOUT WITH CSV HEADER",
|
|
||||||
]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
completed = subprocess.run(
|
with psycopg2.connect(
|
||||||
command,
|
host=config.analytics_db_host,
|
||||||
check=True,
|
port=config.analytics_db_port,
|
||||||
capture_output=True,
|
user=config.analytics_db_user,
|
||||||
text=True,
|
password=config.analytics_db_password,
|
||||||
env=env,
|
dbname=config.analytics_db_name,
|
||||||
)
|
) as conn:
|
||||||
except subprocess.CalledProcessError as exc:
|
with conn.cursor() as cur:
|
||||||
detail = exc.stderr.strip() or exc.stdout.strip()
|
cur.execute("SET TIME ZONE 'Asia/Shanghai';")
|
||||||
raise RuntimeError(f"PostgreSQL 查询失败: {detail}") from exc
|
cur.copy_expert(f"COPY ({query}) TO STDOUT WITH CSV HEADER", output)
|
||||||
|
except psycopg2.Error as exc:
|
||||||
|
raise RuntimeError(f"PostgreSQL 查询失败: {exc}") from exc
|
||||||
|
|
||||||
cleaned_output = "\n".join(
|
output.seek(0)
|
||||||
line for line in completed.stdout.splitlines() if line.strip() and line.strip() != "SET"
|
rows = list(csv.DictReader(output))
|
||||||
)
|
|
||||||
rows = list(csv.DictReader(io.StringIO(cleaned_output)))
|
|
||||||
return {"row_count": len(rows), "rows": rows}
|
return {"row_count": len(rows), "rows": rows}
|
||||||
|
|||||||
@@ -28,7 +28,19 @@ from prefect import flow, get_run_logger, task
|
|||||||
|
|
||||||
from inventory_analytics.logging_utils import exception_fields
|
from inventory_analytics.logging_utils import exception_fields
|
||||||
from inventory_analytics.channel_inventory_sync.entrypoint import main as channel_inventory_sync_main
|
from inventory_analytics.channel_inventory_sync.entrypoint import main as channel_inventory_sync_main
|
||||||
|
from inventory_analytics.channel_inventory_sync.entrypoint import LOG_FILE as CHANNEL_INVENTORY_SYNC_LOG_FILE
|
||||||
from inventory_analytics.batch_inventory_report.cli import main as batch_inventory_report_main
|
from inventory_analytics.batch_inventory_report.cli import main as batch_inventory_report_main
|
||||||
|
from inventory_analytics.batch_inventory_report.service import LOG_FILE as BATCH_INVENTORY_REPORT_LOG_FILE
|
||||||
|
|
||||||
|
|
||||||
|
def read_log_tail(log_file: Path, line_count: int = 80) -> str:
|
||||||
|
try:
|
||||||
|
lines = log_file.read_text(encoding="utf-8", errors="replace").splitlines()
|
||||||
|
except FileNotFoundError:
|
||||||
|
return f"日志文件不存在: {log_file.name}"
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
return f"读取日志文件失败: {exc.__class__.__name__}: {exc}"
|
||||||
|
return "\n".join(lines[-line_count:]) if lines else f"日志文件为空: {log_file.name}"
|
||||||
|
|
||||||
|
|
||||||
@task(name="run-channel-inventory-sync")
|
@task(name="run-channel-inventory-sync")
|
||||||
@@ -58,6 +70,7 @@ def run_channel_inventory_sync_task() -> None:
|
|||||||
root_logger.setLevel(original_level)
|
root_logger.setLevel(original_level)
|
||||||
if exit_code != 0:
|
if exit_code != 0:
|
||||||
logger.error("渠道库存统计失败,退出码=%s", exit_code)
|
logger.error("渠道库存统计失败,退出码=%s", exit_code)
|
||||||
|
logger.error("渠道库存统计日志尾部:\n%s", read_log_tail(CHANNEL_INVENTORY_SYNC_LOG_FILE))
|
||||||
raise RuntimeError(f"渠道库存统计执行失败,退出码: {exit_code}")
|
raise RuntimeError(f"渠道库存统计执行失败,退出码: {exit_code}")
|
||||||
logger.info("渠道库存统计完成,耗时毫秒=%s", int((time.monotonic() - started_at) * 1000))
|
logger.info("渠道库存统计完成,耗时毫秒=%s", int((time.monotonic() - started_at) * 1000))
|
||||||
|
|
||||||
@@ -107,6 +120,7 @@ def run_batch_inventory_report_task(
|
|||||||
root_logger.setLevel(original_level)
|
root_logger.setLevel(original_level)
|
||||||
if exit_code != 0:
|
if exit_code != 0:
|
||||||
logger.error("批次库存统计失败,退出码=%s", exit_code)
|
logger.error("批次库存统计失败,退出码=%s", exit_code)
|
||||||
|
logger.error("批次库存统计日志尾部:\n%s", read_log_tail(BATCH_INVENTORY_REPORT_LOG_FILE))
|
||||||
raise RuntimeError(f"批次库存统计报表执行失败,退出码: {exit_code}")
|
raise RuntimeError(f"批次库存统计报表执行失败,退出码: {exit_code}")
|
||||||
logger.info("批次库存统计完成,耗时毫秒=%s", int((time.monotonic() - started_at) * 1000))
|
logger.info("批次库存统计完成,耗时毫秒=%s", int((time.monotonic() - started_at) * 1000))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user