S16 - some transactional hardening
All checks were successful
Build, test and publish / verify (push) Successful in 7m32s
All checks were successful
Build, test and publish / verify (push) Successful in 7m32s
This commit is contained in:
@@ -27,6 +27,12 @@ public class Database {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs work in a new transaction, or joins the current JTA transaction. Callback registration is supported only
|
||||
* inside transactions started by this instance. Commit callbacks run in registration order after durable commit;
|
||||
* their exceptions propagate to the caller without rolling back committed work or running remaining callbacks.
|
||||
* Rollback callbacks run before the original failure is rethrown; a callback exception replaces that failure.
|
||||
*/
|
||||
public <T> T transaction(final Callable<T> work) throws Exception {
|
||||
try {
|
||||
if (manager.getStatus() != Status.STATUS_NO_TRANSACTION) {
|
||||
@@ -90,10 +96,12 @@ public class Database {
|
||||
}
|
||||
}
|
||||
|
||||
/** Registers a callback on this thread's transaction owned by this instance; see {@link #transaction(Callable)}. */
|
||||
public void afterCommit(final Runnable action) {
|
||||
committed.get().add(action);
|
||||
}
|
||||
|
||||
/** Registers a rollback callback under the same ownership requirement as {@link #afterCommit(Runnable)}. */
|
||||
public void afterRollback(final Runnable action) {
|
||||
rolledBack.get().add(action);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import nl.agilecc.agiledancers.model.scheduling.SchedulingResult;
|
||||
import nl.agilecc.agiledancers.model.scheduling.SchedulingRun;
|
||||
import nl.agilecc.agiledancers.model.scheduling.SchedulingState;
|
||||
import nl.agilecc.agiledancers.model.scheduling.SchedulingSummary;
|
||||
import nl.agilecc.agiledancers.repository.StorageException;
|
||||
import nl.agilecc.agiledancers.service.port.SchedulingEngine;
|
||||
|
||||
/** Owns background tasks; the school monitor orders short commits and publication, never solver computation. */
|
||||
@@ -173,15 +174,42 @@ public class SchedulingRuns {
|
||||
|
||||
private void finish(final SchedulingRun completed) {
|
||||
try {
|
||||
work(() -> {
|
||||
save(completed);
|
||||
return null;
|
||||
});
|
||||
while (true) {
|
||||
try {
|
||||
work(() -> {
|
||||
schools.show(completed.schoolId(), completed.showId());
|
||||
save(completed);
|
||||
return null;
|
||||
});
|
||||
return;
|
||||
} catch (final StorageException unavailable) {
|
||||
// Keep the run guard and terminal outcome until storage recovers; never publish an uncommitted
|
||||
// status.
|
||||
if (executor.isShutdown() || !waitForStorage()) {
|
||||
return;
|
||||
}
|
||||
} catch (final ManagementException removed) {
|
||||
if (removed.getKind() != ManagementExceptionKind.NOT_FOUND) {
|
||||
throw removed;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
schools.endScheduling(completed.showId());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean waitForStorage() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
return true;
|
||||
} catch (final InterruptedException stopping) {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void save(final SchedulingRun run) {
|
||||
if (persistence == null) {
|
||||
publish(run);
|
||||
|
||||
Reference in New Issue
Block a user