Python 长时间运行过程中的SQLAlchemy会话管理

Python 长时间运行过程中的SQLAlchemy会话管理,python,sqlalchemy,wonderware,Python,Sqlalchemy,Wonderware,情景: 基于.NET的应用程序服务器()承载自动化对象,这些对象与工厂中的各种设备进行通信 CPython托管在此应用程序服务器内(使用) 自动化对象具有内置的脚本功能(使用基于.NET的自定义语言)。这些脚本调用Python函数 Python函数是跟踪工厂车间正在进行的工作的系统的一部分。系统的目的是跟踪流程中生成的小部件,确保小部件以正确的顺序通过流程,并检查流程中是否满足某些条件。小部件生产历史和小部件状态存储在关系数据库中,这是SQLAlchemy发挥作用的地方 例如,当小部件通过扫

情景:

  • 基于.NET的应用程序服务器()承载自动化对象,这些对象与工厂中的各种设备进行通信
  • CPython托管在此应用程序服务器内(使用)
  • 自动化对象具有内置的脚本功能(使用基于.NET的自定义语言)。这些脚本调用Python函数
Python函数是跟踪工厂车间正在进行的工作的系统的一部分。系统的目的是跟踪流程中生成的小部件,确保小部件以正确的顺序通过流程,并检查流程中是否满足某些条件。小部件生产历史和小部件状态存储在关系数据库中,这是SQLAlchemy发挥作用的地方

例如,当小部件通过扫描仪时,自动化软件会触发以下脚本(用应用程序服务器的自定义脚本语言编写):

脚本调用
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())
我希望将会话管理排除在基本功能之外。原因有二:

  • 还有另一类函数,序列函数。序列函数调用几个基本函数。一个序列函数应等于一个数据库事务
  • 我需要能够使用其他环境中的库。a) 来自TurboGears web应用程序。在这种情况下,会话管理由TurboGears完成。b) 从一个IPython外壳上。在这种情况下,提交/回滚将是显式的

  • (对于这个冗长的问题,我真的很抱歉。但是我觉得我需要解释这个场景。也许没有必要?

    所描述的装饰器适用于长时间运行的应用程序,但是如果在请求之间意外地共享对象,您可能会遇到麻烦。要使错误显示得更早,并且不损坏任何内容,最好使用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()