장기 실행 프로세스에서 SQLALCHEMY 세션 관리
-
07-07-2019 - |
문제
대본:
- .NET 기반 애플리케이션 서버 (Wonderware IAS/시스템 플랫폼) 공장 바닥의 다양한 장비와 통신하는 자동화 객체를 호스트합니다.
- Cpython 은이 응용 프로그램 서버 내에서 호스팅됩니다 (사용 .NET 용 Python).
- 자동화 객체에는 스크립팅 기능이 내장되어 있습니다 (사용자 정의 .NET 기반 언어 사용). 이 스크립트는 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
파이썬 기능 :
# 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)
의문: 위의 데코레이터는 장기 실행 프로세스에서 세션을 처리하는 데 적합합니까? 전화해야합니다 session.remove()
?
SQLALCHEMY 세션 객체는 스코어 세션입니다.
# pywip/database.py
from sqlalchemy.orm import scoped_session, sessionmaker
session = scoped_session(sessionmaker())
세션 관리를 기본 기능에서 유지하고 싶습니다. 두 가지 이유로 :
- 다른 기능, 시퀀스 기능이 있습니다. 시퀀스 기능은 여러 기본 기능을 호출합니다. 하나의 시퀀스 함수는 하나의 데이터베이스 트랜잭션과 같아야합니다.
- 다른 환경에서 도서관을 사용할 수 있어야합니다. a) 터보 가어스 웹 애플리케이션에서. 이 경우 세션 관리는 터보 가어에 의해 수행됩니다. b) Ipython 쉘에서. 이 경우 커밋/롤백이 명시 적입니다.
(긴 질문에 대해 정말 죄송합니다.하지만 시나리오를 설명해야한다고 느꼈습니다. 아마도 필요하지 않습니까?)
해결책
설명 된 데코레이터는 장기적인 응용 프로그램에 적합하지만 실수로 요청간에 객체를 공유하면 문제가 발생할 수 있습니다. 오류가 더 일찍 나타나고 손상되지 않도록하려면 세션을 사용하여 세션을 폐기하는 것이 좋습니다. 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')
쿼리에서 유효성 검사가 오래된 데이터에서 실행되지 않습니다.
다른 팁
Wonderware 관리자에게 Wonderware Historian에 액세스 할 수 있도록 요청하십시오. SQLALCHEMY를 통해 MSSQL 통화를 통해 태그 값을 매우 쉽게 추적하여 자주 투표 할 수 있습니다.
또 다른 옵션은 Archestra 툴킷을 사용하여 내부 태그 업데이트를 듣고 서버를 Galaxy에서 플랫폼으로 배포하는 것입니다.