我刚刚完成将 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 的预写逻辑中还是其他什么?我已经尝试了提交和刷新的所有可能组合,以强制对数据库进行这些最终更新,并且没有骰子。
需要明确的是,我不会在写入或其他任何事情的过程中中断应用程序,我会在这些写入完成后退出并重新启动它。就像我确信我可以运行该应用程序一天,并且这些特定的写入在退出后都不会持续存在。另外,我在我的应用程序中优雅地处理键盘中断,包括最终的数据库提交以达到良好的效果。
我错过了什么?我需要对鸭子做一些特别的事情吗?
大神,终于明白了。事实证明.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)
这对我有用。