83: Remove lifecycle operations from the EvelynIOUBurnerService API

This commit is contained in:
2026-09-04 10:04:47 +02:00
parent 681b6feef1
commit b6a6d544b5
11 changed files with 183 additions and 111 deletions
@@ -58,34 +58,15 @@ import java.util.List;
* repeats the completed burn.</li>
* </ol>
*
* <p>One dedicated worker begins immediately on {@link #start()}, uses fixed
* <p>One dedicated worker begins immediately when the Hub starts the reference
* implementation through its separate {@code NenjimProcess} view, uses fixed
* delay measured after each completed iteration, and never overlaps
* iterations. {@link #stop()} prevents new iterations and stops that worker.
* Pending signatures and swap/burn suspension flags are process-local only
* and are deliberately reset by a completed explicit stop/start cycle or a
* process restart. Such a reset forgets unknown transaction state and can
* weaken duplicate prevention; operators should reconcile uncertain on-chain
* activity before deliberately restarting a suspended or pending service.</p>
* iterations. This service view currently exposes no domain operations and no
* lifecycle control. Pending signatures and swap/burn suspension flags are
* process-local only and are reset by a process restart. Such a reset forgets
* unknown transaction state and can weaken duplicate prevention; operators
* should reconcile uncertain on-chain activity before deliberately restarting
* a suspended or pending process.</p>
*/
public interface EvelynIOUBurnerService extends NenjimComponent {
/**
* Starts the dedicated worker and begins the first iteration immediately.
*
* @throws IllegalStateException if this instance is already running or a
* prior worker has not terminated cleanly
*/
void start();
/**
* Prevents new iterations, interrupts current processing, and stops the
* dedicated worker cleanly.
*
* <p>A completed stop clears process-local pending and suspension state.
* If the calling thread is interrupted while waiting for termination, its
* interrupt status is preserved.</p>
*
* @throws IllegalStateException if clean worker termination cannot be
* established
*/
void stop();
}
@@ -46,7 +46,9 @@ import static com.r35157.assetaz.services.cis.CurrencyTypeIds.USDT_ID;
import static com.r35157.assetaz.services.cis.ExternalCurrencyReference.SOLANA_MINT_NAMESPACE;
/**
* Reference implementation of the Evelyn IOU buyback-and-burn lifecycle.
* Reference Evelyn IOU burner whose domain service view is exposed through
* {@link EvelynIOUBurnerService} and whose startup is owned by the Hub through
* {@link NenjimProcess}.
*/
public final class EvelynIOUBurnerServiceImpl
implements EvelynIOUBurnerService, NenjimProcess {
@@ -202,9 +204,9 @@ public final class EvelynIOUBurnerServiceImpl
@Override
public synchronized void start() {
if (worker != null || stopping) {
if (worker != null) {
throw new IllegalStateException(
"Evelyn IOU burner is already running or stopping"
"Evelyn IOU burner is already running"
);
}
@@ -247,70 +249,12 @@ public final class EvelynIOUBurnerServiceImpl
}
}
@Override
public void stop() {
ScheduledExecutorService workerToStop;
synchronized (this) {
if (worker == null) {
resetProcessLocalState();
return;
}
if (stopping) {
throw new IllegalStateException(
"Evelyn IOU burner is already stopping"
);
}
stopping = true;
workerToStop = worker;
}
workerToStop.shutdownNow();
boolean terminated;
try {
terminated = workerToStop.awaitTermination(
WORKER_TERMINATION_TIMEOUT_SECONDS,
TimeUnit.SECONDS
);
} catch (InterruptedException exception) {
workerToStop.shutdownNow();
boolean terminatedAfterInterruption = workerToStop.isTerminated();
synchronized (this) {
if (terminatedAfterInterruption && worker == workerToStop) {
worker = null;
resetProcessLocalState();
}
stopping = false;
}
Thread.currentThread().interrupt();
throw new IllegalStateException(
"Interrupted while stopping Evelyn IOU burner",
exception
);
}
synchronized (this) {
if (!terminated) {
stopping = false;
throw new IllegalStateException(
"Evelyn IOU burner worker did not terminate cleanly"
);
}
if (worker == workerToStop) {
worker = null;
}
resetProcessLocalState();
stopping = false;
}
}
private void runIterationSafely() {
try {
runIteration();
} catch (InterruptedException exception) {
Thread.currentThread().interrupt();
if (!isStopping()) {
log.warn("Evelyn IOU burner iteration was interrupted");
}
log.warn("Evelyn IOU burner iteration was interrupted");
} catch (RuntimeException exception) {
log.error(
"Unexpected Evelyn IOU burner iteration failure",
@@ -991,10 +935,6 @@ public final class EvelynIOUBurnerServiceImpl
return duration;
}
private synchronized boolean isStopping() {
return stopping;
}
private void resetProcessLocalState() {
pendingBurn = null;
swapsSuspended = false;
@@ -1011,7 +951,6 @@ public final class EvelynIOUBurnerServiceImpl
private static final int MAXIMUM_SLIPPAGE_BPS = 10000;
private static final ΩamountDecimalsΩ NATIVE_SOLANA_DECIMALS = 9;
private static final ΩamountDecimalsΩ MAXIMUM_SPL_TOKEN_DECIMALS = 255;
private static final long WORKER_TERMINATION_TIMEOUT_SECONDS = 10;
private static final String WORKER_THREAD_NAME =
"evelyn-iou-buyback-and-burner";
@@ -1032,7 +971,6 @@ public final class EvelynIOUBurnerServiceImpl
private final TradingPair eveUsdtTradingPair;
private ScheduledExecutorService worker;
private boolean stopping;
private boolean swapsSuspended;
private boolean burnsSuspended;
private PendingBurn pendingBurn;