Skip to content

Commit

Permalink
Favor distinct methods rather than runner(TransactionSemantics) as an…
Browse files Browse the repository at this point in the history
… entrypoint to create runners
  • Loading branch information
yrodiere committed Dec 20, 2022
1 parent b355383 commit 00c4167
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 45 deletions.
19 changes: 11 additions & 8 deletions docs/src/main/asciidoc/transaction.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,14 @@ public class TransactionExample {
}
public void runnerExample() {
QuarkusTransaction.runner(TransactionSemantic.REQUIRE_NEW).run(() -> {
QuarkusTransaction.requiringNew().run(() -> {
//do work
});
QuarkusTransaction.joiningExisting().run(() -> {
//do work
});
int result = QuarkusTransaction.runner(TransactionSemantic.REQUIRE_NEW)
int result = QuarkusTransaction.requiringNew()
.timeout(10)
.exceptionHandler((throwable) -> {
if (throwable instanceof SomeException) {
Expand All @@ -207,18 +209,19 @@ example in the method calls begin with a timeout option, and then rolls back the

The second method shows the use of lambda scoped transactions with `QuarkusTransaction.runner(...)`;
the first example just runs a `Runnable` within a new transaction,
the second calls a `Callable` with some specific options.
the second does the same but joining the existing transaction (if any),
and the third calls a `Callable` with some specific options.
In particular the `exceptionHandler` method can be used to control if the transaction is rolled back or not on exception.

The following semantics are supported:


DISALLOW_EXISTING::
`QuarkusTransaction.disallowingExisting()`/`DISALLOW_EXISTING`::

If a transaction is already associated with the current thread a `QuarkusTransactionException` will be thrown,
otherwise a new transaction is started, and follows all the normal lifecycle rules.

JOIN_EXISTING::
`QuarkusTransaction.joiningExisting()`/`JOIN_EXISTING`::

If no transaction is active then a new transaction will be started, and committed when the method ends.
If an exception is thrown the exception handler registered by `#exceptionHandler(Function)` will be called to
Expand All @@ -228,14 +231,14 @@ exception is thrown the exception handler will be called, however
a result of `ExceptionResult#ROLLBACK` will result in the TX marked as rollback only, while a result of
`ExceptionResult#COMMIT` will result in no action being taken.

REQUIRE_NEW::
`QuarkusTransaction.requiringNew()`/`REQUIRE_NEW`::

If an existing transaction is already associated with the current thread then the transaction is suspended,
then a new transaction is started which follows all the normal lifecycle rules,
and when it's complete the original transaction is resumed.
Otherwise, a new transaction is started, and follows all the normal lifecycle rules.

SUSPEND_EXISTING::
`QuarkusTransaction.suspendingExisting()`/`SUSPEND_EXISTING`::

If no transaction is active then these semantics are basically a no-op.
If a transaction is active then it is suspended, and resumed after the task is run.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public void testPropertiesPropagatedToRuntimeInit() {
public void testInsertsOrdered() {
var listener = new BatchCountSpyingEventListener();

QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).run(() -> {
QuarkusTransaction.requiringNew().run(() -> {
em.unwrap(Session.class).addEventListeners(listener);

ParentEntity parent1 = new ParentEntity(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import io.quarkus.narayana.jta.QuarkusTransaction;
import io.quarkus.narayana.jta.QuarkusTransactionException;
import io.quarkus.narayana.jta.TransactionExceptionResult;
import io.quarkus.narayana.jta.TransactionSemantics;
import io.quarkus.test.QuarkusUnitTest;

public class TransactionRunnerTest {
Expand All @@ -38,26 +37,26 @@ public class TransactionRunnerTest {
@Test
public void commit() {
var sync = new TestSync();
QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).run(() -> register(sync));
QuarkusTransaction.requiringNew().run(() -> register(sync));
assertEquals(Status.STATUS_COMMITTED, sync.completionStatus);

assertEquals(Status.STATUS_COMMITTED,
QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).call(this::register).completionStatus);
QuarkusTransaction.requiringNew().call(this::register).completionStatus);
}

@Test
public void rollback() {
var sync1 = new TestSync();
assertThrows(QuarkusTransactionException.class,
() -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).run(() -> {
() -> QuarkusTransaction.requiringNew().run(() -> {
register(sync1);
QuarkusTransaction.rollback();
}));
assertEquals(Status.STATUS_ROLLEDBACK, sync1.completionStatus);

var sync2 = new TestSync();
assertThrows(QuarkusTransactionException.class,
() -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).call(() -> {
() -> QuarkusTransaction.requiringNew().call(() -> {
register(sync2);
QuarkusTransaction.rollback();
return null;
Expand All @@ -69,15 +68,15 @@ public void rollback() {
public void rollbackOnly() {
var sync1 = new TestSync();
assertThrows(QuarkusTransactionException.class,
() -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).run(() -> {
() -> QuarkusTransaction.requiringNew().run(() -> {
register(sync1);
QuarkusTransaction.setRollbackOnly();
}));
assertEquals(Status.STATUS_ROLLEDBACK, sync1.completionStatus);

var sync2 = new TestSync();
assertThrows(QuarkusTransactionException.class,
() -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).call(() -> {
() -> QuarkusTransaction.requiringNew().call(() -> {
register(sync2);
QuarkusTransaction.setRollbackOnly();
return null;
Expand All @@ -88,7 +87,7 @@ public void rollbackOnly() {
@Test
public void timeout() {
var sync1 = new TestSync();
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.requiringNew()
.timeout(1)
.run(() -> {
register(sync1);
Expand All @@ -101,7 +100,7 @@ public void timeout() {
assertEquals(Status.STATUS_ROLLEDBACK, sync1.completionStatus);

var sync2 = new TestSync();
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.requiringNew()
.timeout(1)
.call(() -> {
register(sync2);
Expand All @@ -118,23 +117,23 @@ public void timeout() {
@Test
public void exception() {
var sync1 = new TestSync();
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.requiringNew()
.run(() -> {
register(sync1);
throw new MyRuntimeException();
}));
assertEquals(Status.STATUS_ROLLEDBACK, sync1.completionStatus);

var sync2 = new TestSync();
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.requiringNew()
.call(() -> {
register(sync2);
throw new MyRuntimeException();
}));
assertEquals(Status.STATUS_ROLLEDBACK, sync2.completionStatus);

var sync3 = new TestSync();
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.requiringNew()
.call(() -> {
register(sync3);
throw new MyCheckedException();
Expand All @@ -145,7 +144,7 @@ public void exception() {
@Test
public void exceptionHandler() {
var sync1 = new TestSync();
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.requiringNew()
.exceptionHandler((e) -> TransactionExceptionResult.COMMIT)
.run(() -> {
register(sync1);
Expand All @@ -154,7 +153,7 @@ public void exceptionHandler() {
assertEquals(Status.STATUS_COMMITTED, sync1.completionStatus);

var sync2 = new TestSync();
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(MyRuntimeException.class, () -> QuarkusTransaction.requiringNew()
.exceptionHandler((e) -> TransactionExceptionResult.COMMIT)
.call(() -> {
register(sync2);
Expand All @@ -163,7 +162,7 @@ public void exceptionHandler() {
assertEquals(Status.STATUS_COMMITTED, sync2.completionStatus);

var sync3 = new TestSync();
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)
assertThrows(QuarkusTransactionException.class, () -> QuarkusTransaction.requiringNew()
.exceptionHandler((e) -> TransactionExceptionResult.COMMIT)
.call(() -> {
register(sync3);
Expand All @@ -174,48 +173,48 @@ public void exceptionHandler() {

@Test
@ActivateRequestContext
public void suspendExisting() {
public void suspendingExisting() {
QuarkusTransaction.begin();
assertTrue(QuarkusTransaction.isActive());
QuarkusTransaction.runner(TransactionSemantics.SUSPEND_EXISTING)
QuarkusTransaction.suspendingExisting()
.run(() -> assertFalse(QuarkusTransaction.isActive()));
assertTrue(QuarkusTransaction.isActive());
QuarkusTransaction.rollback();

assertFalse(QuarkusTransaction.isActive());
QuarkusTransaction.runner(TransactionSemantics.SUSPEND_EXISTING)
QuarkusTransaction.suspendingExisting()
.run(() -> assertFalse(QuarkusTransaction.isActive()));
assertFalse(QuarkusTransaction.isActive());
}

@Test
@ActivateRequestContext
public void disallowExisting() {
public void disallowingExisting() {
assertFalse(QuarkusTransaction.isActive());
assertEquals(Status.STATUS_COMMITTED,
QuarkusTransaction.runner(TransactionSemantics.DISALLOW_EXISTING).call(this::register).completionStatus);
QuarkusTransaction.disallowingExisting().call(this::register).completionStatus);
assertFalse(QuarkusTransaction.isActive());

QuarkusTransaction.begin();
assertTrue(QuarkusTransaction.isActive());
assertThrows(QuarkusTransactionException.class,
() -> QuarkusTransaction.runner(TransactionSemantics.DISALLOW_EXISTING).call(this::register));
() -> QuarkusTransaction.disallowingExisting().call(this::register));
assertTrue(QuarkusTransaction.isActive());
QuarkusTransaction.rollback();
}

@Test
@ActivateRequestContext
public void requireNew() throws SystemException {
public void requiringNew() throws SystemException {
assertFalse(QuarkusTransaction.isActive());
assertEquals(Status.STATUS_COMMITTED,
QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).call(this::register).completionStatus);
QuarkusTransaction.requiringNew().call(this::register).completionStatus);
assertFalse(QuarkusTransaction.isActive());

QuarkusTransaction.begin();
assertTrue(QuarkusTransaction.isActive());
var tx = transactionManager.getTransaction();
assertEquals(Status.STATUS_COMMITTED, QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW).call(() -> {
assertEquals(Status.STATUS_COMMITTED, QuarkusTransaction.requiringNew().call(() -> {
assertTrue(QuarkusTransaction.isActive());
assertNotEquals(tx, transactionManager.getTransaction());
return register();
Expand All @@ -226,16 +225,16 @@ public void requireNew() throws SystemException {

@Test
@ActivateRequestContext
public void joinExisting() throws SystemException {
public void joiningExisting() throws SystemException {
assertFalse(QuarkusTransaction.isActive());
assertEquals(Status.STATUS_COMMITTED,
QuarkusTransaction.runner(TransactionSemantics.JOIN_EXISTING).call(this::register).completionStatus);
QuarkusTransaction.joiningExisting().call(this::register).completionStatus);
assertFalse(QuarkusTransaction.isActive());

QuarkusTransaction.begin();
assertTrue(QuarkusTransaction.isActive());
var tx = transactionManager.getTransaction();
QuarkusTransaction.runner(TransactionSemantics.JOIN_EXISTING).call(() -> {
QuarkusTransaction.joiningExisting().call(() -> {
assertTrue(QuarkusTransaction.isActive());
assertEquals(tx, transactionManager.getTransaction());
return null;
Expand Down
Loading

0 comments on commit 00c4167

Please sign in to comment.