Python 长时间运行过程中的SQLAlchemy会话管理
情景:Python 长时间运行过程中的SQLAlchemy会话管理,python,sqlalchemy,wonderware,Python,Sqlalchemy,Wonderware,情景: 基于.NET的应用程序服务器()承载自动化对象,这些对象与工厂中的各种设备进行通信 CPython托管在此应用程序服务器内(使用) 自动化对象具有内置的脚本功能(使用基于.NET的自定义语言)。这些脚本调用Python函数 Python函数是跟踪工厂车间正在进行的工作的系统的一部分。系统的目的是跟踪流程中生成的小部件,确保小部件以正确的顺序通过流程,并检查流程中是否满足某些条件。小部件生产历史和小部件状态存储在关系数据库中,这是SQLAlchemy发挥作用的地方 例如,当小部件通过扫
- 基于.NET的应用程序服务器()承载自动化对象,这些对象与工厂中的各种设备进行通信
- CPython托管在此应用程序服务器内(使用)
- 自动化对象具有内置的脚本功能(使用基于.NET的自定义语言)。这些脚本调用Python函数
widgetscan
python函数:
# pywip/functions.py
from pywip.database import session
from pywip.model import Widget, WidgetHistoryItem
from pywip import validation, StatusMessage
from datetime import datetime
def WidgetScanned(widget_id, scanner_id):
widget = session.query(Widget).get(widget_id)
validation.validate_widget_passed_scanner(widget, scanner) # raises exception on error
widget.history.append(WidgetHistoryItem(timestamp=datetime.now(), action=u"SCANNED", scanner_id=scanner_id))
widget.last_scanner = scanner_id
widget.last_update = datetime.now()
return StatusMessage("OK")
# ... there are a dozen similar functions
我的问题是:在这种情况下,如何最好地管理SQLAlchemy会话?应用程序服务器是一个长期运行的过程,通常在重启之间运行数月。应用服务器是单线程的
目前,我的做法如下:
我将装饰器应用于我使应用程序服务器可用的函数:
# pywip/iasfunctions.py
from pywip import functions
def ias_session_handling(func):
def _ias_session_handling(*args, **kwargs):
try:
retval = func(*args, **kwargs)
session.commit()
return retval
except:
session.rollback()
raise
return _ias_session_handling
# ... actually I populate this module with decorated versions of all the functions in pywip.functions dynamically
WidgetScanned = ias_session_handling(functions.WidgetScanned)
问题:上面的decorator是否适合处理长时间运行的进程中的会话?我应该调用session.remove()
SQLAlchemy会话对象是作用域会话:
# pywip/database.py
from sqlalchemy.orm import scoped_session, sessionmaker
session = scoped_session(sessionmaker())
我希望将会话管理排除在基本功能之外。原因有二:
(对于这个冗长的问题,我真的很抱歉。但是我觉得我需要解释这个场景。也许没有必要?所描述的装饰器适用于长时间运行的应用程序,但是如果在请求之间意外地共享对象,您可能会遇到麻烦。要使错误显示得更早,并且不损坏任何内容,最好使用session.remove()放弃会话 或者如果您可以将
与上下文管理器一起使用:
try:
with session.registry().transaction:
return func(*args, **kwargs)
finally:
session.remove()
顺便说一句,您可能希望在查询中使用。使用_lockmode('update')
,这样您的验证就不会在过时的数据上运行。请您的WonderWare管理员允许您访问WonderWare Historian,您可以通过MSSQL调用通过sqlalchemy非常轻松地跟踪标记的值,您可以经常进行轮询
另一个选择是使用archestra工具包来监听内部标记更新,并在galaxy中部署一个服务器作为平台,您可以从中监听
try:
try:
retval = func(*args, **kwargs)
session.commit()
return retval
except:
session.rollback()
raise
finally:
session.remove()
try:
with session.registry().transaction:
return func(*args, **kwargs)
finally:
session.remove()