退出 Flask 时丢失 duckdb 条目

问题描述 投票:0回答:1

我刚刚完成将 Flask 应用程序从 Postgres 迁移到 DuckDB,几乎一切似乎都运行良好。有一个非常奇怪的问题,尽管我已经用头撞墙好几个小时了,但似乎无法弄清楚它的情况。

在我的 Flask 路线之一中,会发生与用户上传的内容相关的各种事情。在处理过程中,文件通过应用程序更新数据库中的几个不同表。应用程序中的一切看起来 100% 正常且正确,但当我退出 Flask 时,最后三个表更新就消失了。给定的 Flask 路线确实又长又复杂,但一切都像以前一样完美,直到某个点......

   ** whole bunch of stuff happens above here **
    
    try:    
        db.session.commit()
    except Exception as e:
        db.session.rollback()

    
    db.session.add(new_audit_history_entry)
    db.session.add(new_audit_log_entry)


    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()

    update_task = TaskQueue.query.get(task_id)
    update_task.completed_at = datetime.now()
    update_task.status = 'Complete'

    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
    finally:
        audit_history = AuditHistory.query.all()
        audit_logs = AuditLog.query.all()
        tasks = TaskQueue.query.all()
        db.session.flush()
        db.session.close()

        return jsonify({'message': 'Files saved and validated!', 'This many files: ': len(files)})

我没有收到任何错误,应用程序中的一切看起来都很正常 - 我可以看到我期望看到的所有内容。一切都很好。但如果我退出 Flask(CLI 中的 ctl+c),从

db.session.add(new_audit_history_entry)
开始的所有内容都会消失。 audit_history 和audit_log 表中的条目消失,并且TaskQueue 表已恢复到上次更新时的路由中的状态(在最终提交到上面看到的该表之前)。

我看到的唯一提示是当我启动 Flask 备份时,我得到以下信息:

Exception in WAL playback: Violates foreign key constraint because key "auditid: 95693563-b229-40d7-9b12-5c4447bdb601" does not exist in the referenced table

那么看来那些最终提交没有被完全保存?它们仅保存在 Duck 的预写逻辑中还是其他什么?我已经尝试了提交和刷新的所有可能组合,以强制对数据库进行这些最终更新,并且没有骰子。

需要明确的是,我不会在写入或其他任何事情的过程中中断应用程序,我会在这些写入完成后退出并重新启动它。就像我确信我可以运行该应用程序一天,并且这些特定的写入在退出后都不会持续存在。另外,我在我的应用程序中优雅地处理键盘中断,包括最终的数据库提交以达到良好的效果。

我错过了什么?我需要对鸭子做一些特别的事情吗?

python flask sqlalchemy flask-sqlalchemy duckdb
1个回答
0
投票

大神,终于明白了。事实证明.commit()和.close()不会自动触发WAL文件与静态DB文件的同步。

您需要调用

CHECKPOINT
文档此处)来强制同步。 Python API 没有为此内置任何内容,因此您需要将其作为 SQL 执行。就我而言,使用 SQLalchemy,我将
db.engine.execute('CHECKPOINT;')
添加到我的“优雅退出”函数中:

def handler(signal_received, frame):
    with app.app_context():
        print('SIGINT or CTRL-C detected. Gracefully exiting')
        # Force a checkpoint in DuckDB to synchronize WAL with the main database
        try:
            db.engine.execute('CHECKPOINT;')
            print("Database CHECKPOINT completed.")
        except Exception as e:
            print(f"Failed to execute CHECKPOINT: {e}")
        db.session.commit()
        db.session.close()
        exit(0)

这对我有用。

© www.soinside.com 2019 - 2024. All rights reserved.