Flask集成OpenAI Assistant进程被Killed,内存泄漏问题排查与修复
问题原因分析
终端显示“Killed”通常是系统因**内存耗尽(OOM)**主动终止进程,你的代码主要问题出在以下几点:
- 空闲会话清理时机不合理:
kill_idle_sessions()仅在用户发起请求时才会执行,如果服务器长时间没有新请求,空闲会话会一直占用内存无法释放,最终导致内存耗尽。 - 未释放远程会话资源:删除本地
Session对象时,没有调用OpenAI API删除对应的远程Thread资源,本地对象销毁后,远程资源的客户端引用可能存在隐性内存泄漏。 - 异常场景下会话残留:请求中途失败时,新创建的Session可能未被及时清理,持续占用内存。
修复方案
1. 改用定时任务自动清理空闲会话
创建独立线程定时执行清理逻辑,确保即使没有用户请求,也能定期释放内存:
def start_session_cleanup_thread(): def cleanup_loop(): while True: kill_idle_sessions() time.sleep(60) # 每分钟执行一次清理 cleanup_thread = threading.Thread(target=cleanup_loop, daemon=True) cleanup_thread.start() # 在app初始化后启动定时清理线程 if __name__ == '__main__': start_session_cleanup_thread() app.run(debug=False, ssl_context=..., host='0.0.0.0')
2. 清理Session时同步删除远程Thread
修改kill_idle_sessions()函数,删除本地Session前调用OpenAI API销毁远程Thread,彻底释放资源:
def kill_idle_sessions(): for sid in list(sessions.keys()): scls = sessions[sid] if time.time() - scls.last_request > 60*15: # 删除远程Thread try: client.beta.threads.delete(scls.thread.id) logger.info(f'Deleted remote thread {scls.thread.id} for session {sid}') except Exception as e: logger.error(f'Failed to delete thread {scls.thread.id}: {e}') # 删除本地Session del sessions[sid] logger.info(f'Killed {sid} due to idle')
3. 优化异常场景下的Session清理
在ask接口中,确保请求失败时新创建的Session能被及时删除:
@app.route('/ask', methods=['POST']) def ask(): """API method to ask the assistant a question""" new_session_created = False session_id = None try: # has session id cookie? session_id = request.json.get('session_id', None) has_session = session_id is not None if not has_session: session_id = uuid.uuid4().hex new_session_created = True if has_session and session_id not in sessions: return jsonify(dict(type="error", error="Invalid session id")) question = request.json['question'] resp = dict(type="success", response="What do you mean by that...?") if not has_session: resp['session_id'] = session_id sessions[session_id] = Session(session_id) sess: Session = sessions[session_id] ans = sess.ask(question) # save to database ip = request.environ.get('HTTP_X_FORWARDED_FOR') or request.environ.get('REMOTE_ADDR') or "unknown" with dblock: db.execute('INSERT INTO queries (ip, question, answer) VALUES (?, ?, ?)', (ip, question, ans)) db.commit() resp['response'] = ans return jsonify(resp) except Exception as e: traceback.print_exc() logger.error(f'Error: {e}', exc_info=True) # 若为新创建的Session,异常时删除避免内存泄漏 if new_session_created and session_id in sessions: del sessions[session_id] logger.info(f'Deleted new session {session_id} due to error') return jsonify(dict(type="error", error=f"server error occured, check logs."))
4. 生产环境替换Flask内置服务器
Flask默认开发服务器内存管理和并发能力有限,建议改用gunicorn等生产级服务器,配合进程数限制控制内存:
# 安装gunicorn pip install gunicorn # 启动服务器(限制为4个工作进程) gunicorn --workers 4 --bind 0.0.0.0:5000 your_app_module:app
内容的提问来源于stack exchange,提问作者Verify
相关产品推荐
相关产品推荐

