You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在asyncio任务中调用Postgres NOW()返回错误时间的问题

PostgreSQL NOW()返回时间偏差,与本地时间不一致的问题解决

问题现象

  • 程序每小时定时执行,日志记录的datetime.datetime.now()时间正确,但PostgreSQL的NOW()函数返回的时间逐渐滞后
  • 程序启动后首次执行时NOW()时间正常,后续每次执行偏差持续增大
  • 通过psql、PyCharm等客户端连接数据库时,NOW()能返回正确的实时时间

问题根源

PostgreSQL的NOW()函数返回的是当前数据库会话的启动时间,也就是连接建立的时间,而非查询执行时的实时时间。

你的程序使用单例模式维护了一个持久化的数据库长连接,每次调用NOW()都会返回这个连接创建时的时间。随着程序运行时长增加,这个时间与实际时间的差距自然会越来越大。而其他客户端每次都是新建连接,所以NOW()能返回正确的实时时间。

解决方案

1. 使用实时时间函数替代NOW()

将查询语句中的SELECT NOW()替换为以下任意一种,获取实时时间:

  • CURRENT_TIMESTAMP:返回当前事务的开始时间,适合大多数业务场景
  • clock_timestamp():返回查询执行瞬间的精确时间,适合需要极高时间精度的场景

修改后的process_validity函数示例:

def process_validity() -> Generator[DataInterface, None, None]:
    # 改用CURRENT_TIMESTAMP获取实时时间
    db_now: datetime.datetime = db.fetchone("SELECT CURRENT_TIMESTAMP")['current_timestamp'].replace(tzinfo=None)
    logger.info("CURRENT_TIMESTAMP is:", db_now)
    for users_set in db.fetchmany("SELECT ...", 100, ()):
        for user in users_set:
            yield user

2. (不推荐)定期重建数据库连接

如果必须使用NOW(),可以在每次任务执行前后重建连接,但这会失去长连接的性能优势,仅作为备选方案:

async def interval_handler():
    while True:
        logger.info("Handler:", datetime.datetime.now())
        # 每次任务前重建连接
        db.connect()
        for data in process_validity():
            pass
        # 任务完成后关闭连接
        db.connection.close()

        # 等待下一小时的逻辑...
        delta = datetime.timedelta(hours=1)
        now = datetime.datetime.now()
        next_hour = (now + delta).replace(microsecond=0, second=0, minute=0)
        wait_seconds = (next_hour - now).seconds
        await asyncio.sleep(1)
        await asyncio.sleep(wait_seconds)

额外注意事项

  • 确认fetchone方法已正确实现(你的代码中仅定义了fetchmany,需保证fetchone能正确执行单行查询)
  • 单例模式下的长连接如果长期闲置,可能会被数据库服务器主动断开,建议添加连接健康检查逻辑

内容的提问来源于stack exchange,提问作者kinton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 04:45:14