Frage

Szenario:

  • Eine .NET-basierten Anwendungsserver ( Wonder IAS / System Platform ) beherbergt Automatisierungsobjekte, die mit verschiedenen Geräten in der Fabrik zu kommunizieren.
  • CPython wird in diesem Anwendungsserver gehostet (unter Verwendung von Python für .NET ).
  • Die Automatisierungsobjekte haben Scripting-Funktionalität eingebaut (eine benutzerdefinierte verwenden, .NET-basierte Sprache). Diese Skripte rufen Python-Funktionen.

Die Python-Funktionen sind Teil eines Systems, Work-in-Fortschritt in der Fabrik zu verfolgen. Der Zweck des Systems ist es, die erzeugten Widgets entlang des Prozesses zu verfolgen, stellen Sie sicher, dass die Widgets in der richtigen Reihenfolge durch den Prozess gehen, und prüfen Sie, dass bestimmte Bedingungen entlang des Prozesses erfüllt sind. Das Widget Produktionsgeschichte und Widget-Zustand in einer relationalen Datenbank gespeichert ist, das ist, wo SQLAlchemy seine Rolle spielt.

Wenn zum Beispiel eines Widget einen Scanner passiert, löst die Automatisierungssoftware die folgenden Skript (geschrieben in dem benutzerdefinierten Skriptsprache des Anwendungsservers):

' 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;

Das Skript ruft die WidgetScanned Python-Funktion:

# 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

Meine Frage ist: Wie am besten ich SQLAlchemy Sitzungen in diesem Szenario verwalten Der Anwendungsserver ist ein lang andauernde Prozess, in der Regel Monate zwischen Neustart ausgeführt wird. Der Anwendungsserver ist single-threaded.

Zur Zeit mache ich es folgendermaßen:

Ich beantrage einen Dekorateur auf die Funktionen, die ich auf dem Anwendungsserver avaliable machen:

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

Frage:? Ist der Dekorateur oben geeignet für Sitzungen in einem langlaufende Prozess der Handhabung Soll ich session.remove() nennen

Das SQLAlchemy-Session-Objekt ist eine scoped Sitzung:

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

session = scoped_session(sessionmaker())

Ich möchte aus den grundlegenden Funktionen des Session-Management halten. Aus zwei Gründen:

  1. Es gibt eine andere Familie von Funktionen, Sequenzfunktionen. Die Sequenzfunktionen aufrufen mehrere der Grundfunktionen. Eine Sequenz-Funktion sollte eine Datenbanktransaktion entsprechen.
  2. Ich brauche die Bibliothek aus anderen Umgebungen verwenden zu können. a) Aus einer Turbogears Web-Anwendung. In diesem Fall wird die Sitzungsverwaltung von Turbogears getan. b) Von einer IPython Shell. In diesem Fall Commit / Rollback explizit sein wird.

(Ich bin wirklich leid für die lange Frage. Aber ich habe das Gefühl erforderlich, um das Szenario zu erklären. Vielleicht nicht notwendig?)

War es hilfreich?

Lösung

Die beschriebene Dekorateur ist für lange laufende Anwendungen geeignet, aber Sie können in Schwierigkeiten geraten, wenn Sie versehentlich Objekte zwischen Anfragen teilen. Um die Fehler erscheinen früher und nicht korrupt etwas es besser ist, die Sitzung mit session.remove () zu verwerfen.

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

Oder wenn Sie den with Kontext-Manager verwenden können:

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

By the way, möchten Sie vielleicht .with_lockmode('update') auf der Abfrage verwenden, um Ihre Validate läuft nicht auf veralteten Daten.

Andere Tipps

Fragen Sie Ihren Administrator Wonder Sie an den Historian Zugang zu geben, können Sie die Werte der Variablen verfolgen ziemlich leicht über MSSQL über sqlalchemy Anrufe, die Sie jeder so oft abfragen kann.

Eine andere Möglichkeit ist es, die ArchestrA-Toolkit zu verwenden für die interne Variable Updates zu hören und einen Server als Plattform in der Galaxie im Einsatz haben, die Sie von hören.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top