0

Ich habe eine PUT-Anfrage, die zu lang ist, um zu laufen. Ich möchte es async machen, indem ich Fortsetzungen benutze (await/promise feature). erstelle ich einen Job (LongJobThatUpdatesThePassedEntity), das ändert meine Einheitplayframework 1.2.x: erwarten/async und JPA-Transaktionen

public static void myLongPut(@required Long id, String someData) { 
     MyJpaModel myJpaModel = MyJpaModel.findById(id); 

     //straightforward modifications 
     updateMyJpaModel(someData); 
     myJpaModel.save(); 

     //long processing modifications to entity, involving WS calls 
     Promise<String> delayedResult = new LongJobThatUpdatesThePassedEntity(id).now(); 

     await(delayedResult); 

     render(myJpaModel.refresh()); 

    } 

Wie werden die DB-Transaktionen verwaltet?

Gibt es vor dem Job einen Commit?

Der Job hat eine eigene DB-Transaktion?

Wenn ein Problem in der , die Rollback, gibt es die updateMyJpaModel vorgenommenen Änderungen bestehen bleiben?

kann ich am Ende render(myJpaModel.refresh()) tun? wird es die geradlinigen Modifikationen und die langen enthalten?

danken der

Antwort

1

Ich kann für Play 1.4.3 meisten Ihrer Frage beantworten, die die Version ich zur Zeit verwenden. Ich erwarte nicht, dass sich seit Play 1.2 so viel geändert hat.

Wie werden die DB-Transaktionen verwaltet?

Spielen! behandelt die Transaktionen für Jobs und Controller-Aktionen mit einem "Aufruf", bei dem es sich um ein Play-spezifisches Konzept handelt. Kurz gesagt, für jeden Aufruf erhält jedes Plugin die Möglichkeit, vor und nach dem Ausführen der aufgerufenen Methode Setup und Bereinigung durchzuführen. Für den Datenbankzugriff startet und schließt die Methode JPAPlugin.withinFilter die Transaktion mithilfe der Hilfsmethoden der JPA-Klasse.

Gibt es vor dem Job einen Commit?

Wenn Sie await(Future<T>) aufrufen, hat dies den Effekt, die aktuelle Transaktion zu schließen und eine neue zu starten. Der spezifische Mechanismus ist, dass er eine "Suspend" -Ausnahme auslöst, die bis zu PlayHandler$NettyInvocation aufblubbert und bewirkt, dass die afterInvocation Callbacks aufgerufen werden. Dies führt dazu, dass JPAPlugin.afterInvocation JPA.closeTx() aufrufen, die die Transaktion je nach Bedarf entweder festschreibt oder zurücksetzt.

Wenn der Job beendet wird und die Fortsetzung von await() fortgesetzt wird. Dies wird auch als Aufruf behandelt. Daher wird die Transaktion wie zuvor unter Verwendung von JPAPlugin.withinFilter() gestartet. Anders als zuvor ist die Controller-Aktion jedoch nicht das Ziel des Aufrufs, sondern ActionInvoker.invoke() ruft invokeWithContinuation auf, wodurch der gespeicherte Fortsetzungsstatus wiederhergestellt wird und die Ausführung durch Rückkehr von await() fortgesetzt wird.

JPA.withTransaction sieht aus wie es einige besondere Logik hat, um den gleichen Entity Manager über die Fortsetzung suspend/resume zu behalten. Ich denke, ohne dies könnten Sie nicht auffrischen() aufrufen.

In Ihrem Code, denke ich, gibt es eine Race-Bedingung zwischen, wenn Wartet() schließt die Transaktion und der Job startet seine Transaktion. Das heißt, es ist möglich, dass die Transaktion des Jobs beginnt, bevor der Controller die Transaktion "vorher warten" festschreibt. Um dies zu vermeiden, können Sie vor dem Aufruf von Job.now() explizit JPA.closeTx() aufrufen.

Basierend auf Code-Inspektion, es sieht aus wie die Art Play! Ist dies der Fall, wird der Job beendet und die Transaktion des Jobs wird geschlossen, bevor die Transaktion "after wait()" geöffnet wird. Ich weiß nicht, ob irgendwelche Dokumentation, die besagt, dass dies ein beabsichtigter Teil des warte() - Vertrags ist, also wenn dies für Ihre Anwendung essentiell ist, können Sie undokumentiertes Verhalten vermeiden, indem Sie die Transaktion kurz bevor Ihre Job.doJobWithResult() Methode zurückgibt.

Der Job hat eine eigene DB-Transaktion?

Ja, es sei denn, es ist annotiert, keine Transaktion zu haben.

Wenn in der LongJobThatUpdatesThePassedEntity ein Rollback auftritt, werden die in updateMyJpaModel vorgenommenen Änderungen beibehalten?

Basierend auf den obigen Erläuterungen sind alle drei Transaktionen unabhängig voneinander. Wenn man zurückgerollt wird, sehe ich nicht, wie es die anderen beeinflussen würde.

+0

Das ist abgeschlossen, ich vermied es endlich mit .refresh() zu spielen und stattdessen Model.findById() nach dem warten zu rufen. –

Verwandte Themen