2009-09-14 33 views
3

場景:的SQLAlchemy會話管理在長期運行過程

  • 基於.NET-A的應用服務器(Wonderware IAS/System Platform)託管該工廠車間與各種設備進行通信的自動化對象。
  • CPython位於此應用程序服務器內部(使用Python for .NET)。
  • 自動化對象具有內置的腳本功能(使用基於.NET的自定義語言)。這些腳本調用Python函數。

Python函數是系統的一部分,用於跟蹤工廠車間的工作進度。系統的目的是跟蹤流程中生成的小部件,確保小部件按照正確的順序遍歷整個過程,並檢查過程中是否滿足某些條件。小部件生產歷史和小部件狀態存儲在關係數據庫中,這是SQLAlchemy發揮其作用的地方。

例如,當某個微件通過掃描儀,自動化軟件觸發以下腳本(寫在應用程序服務器的自定義腳本語言):

' wiget_id and scanner_id provided by automation object 
' ExecFunction() takes care of calling a CPython function 
retval = ExecFunction("WidgetScanned", widget_id, scanner_id); 
' if the python function raises an Exception, ErrorOccured will be true 
' in this case, any errors should cause the production line to stop. 
if (retval.ErrorOccured) then 
    ProductionLine.Running = False; 
    InformationBoard.DisplayText = "ERROR: " + retval.Exception.Message; 
    InformationBoard.SoundAlarm = True 
end if; 

的腳本調用WidgetScanned 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會話?應用程序服務器是一個長時間運行的進程,通常在重新啓動之間運行數月。應用程序服務器是單線程的。

目前,我做了以下方法:

我申請一個裝飾,以我做avaliable到應用服務器的功能:

# 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) 

問:是上述適用於處理會話裝飾在一個漫長的過程中?我應該撥打session.remove()嗎?

的SQLAlchemy的會話對象是一個範圍的會議:

# pywip/database.py 
from sqlalchemy.orm import scoped_session, sessionmaker 

session = scoped_session(sessionmaker()) 

我想保持會話管理出來的基本功能。有兩個原因:

  1. 還有另一個函數序列函數族。序列函數調用幾個基本函數。一個序列函數應該等於一個數據庫事務。
  2. 我需要能夠使用來自其他環境的庫。 a)從TurboGears網絡應用程序。在這種情況下,會話管理由TurboGears完成。 b)從IPython shell。在這種情況下,提交/回滾將是明確的。

(對於這個長期的問題我真的很抱歉,但是我覺得我需要解釋一下這個場景,也許沒有必要?)

回答

4

描述的裝飾器適用於長時間運行的應用程序,但如果您不小心在請求之間共享對象,則可能會遇到麻煩。爲了使錯誤更早出現並且不會損壞任何東西,最好使用session.remove()丟棄會話。

try: 
    try: 
     retval = func(*args, **kwargs) 
     session.commit() 
     return retval 
    except: 
     session.rollback() 
     raise 
finally: 
    session.remove() 

或者,如果你可以使用with情況管理器:

try: 
    with session.registry().transaction: 
     return func(*args, **kwargs) 
finally: 
    session.remove() 

順便說一句,你可能想使用.with_lockmode('update')上查詢,以便您的驗證不陳舊的數據運行。

1

請問您的WonderWare管理員讓您訪問Wonderware Historian,您可以通過sqlalchemy上的MSSQL調用很容易地跟蹤標籤的值,您可以頻繁地進行輪詢。

另一種選擇是使用archestra工具包來偵聽內部標記更新並將服務器部署爲銀河系中可以偵聽的平臺。