IDEMPIERE-5763 Improve reliability of stopping a scheduler (#1885)

This commit is contained in:
hengsin 2023-06-08 03:28:32 +08:00 committed by GitHub
parent f832d496e3
commit acab52e9a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 49 additions and 7 deletions

View File

@ -25,6 +25,7 @@ import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.base.Core; import org.adempiere.base.Core;
@ -467,10 +468,7 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer<IServerFacto
LocalServerController server = servers[i]; LocalServerController server = servers[i];
try try
{ {
if (server.scheduleFuture != null && !server.scheduleFuture.isDone()) server.stop();
{
server.scheduleFuture.cancel(true);
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -548,7 +546,7 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer<IServerFacto
try try
{ {
server.scheduleFuture.cancel(true); server.stop();
Thread.sleep(10); // 1/100 sec Thread.sleep(10); // 1/100 sec
} }
catch (Exception e) catch (Exception e)
@ -731,11 +729,15 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer<IServerFacto
return m_start; return m_start;
} // getStartTime } // getStartTime
/**
* Controller for background server thread
*/
private class LocalServerController implements Runnable private class LocalServerController implements Runnable
{ {
protected AdempiereServer server; protected AdempiereServer server;
protected volatile ScheduledFuture<?> scheduleFuture; protected volatile ScheduledFuture<?> scheduleFuture;
protected AtomicBoolean stop;
private LocalServerController(AdempiereServer server) { private LocalServerController(AdempiereServer server) {
this(server, true); this(server, true);
@ -743,22 +745,47 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer<IServerFacto
private LocalServerController(AdempiereServer server, boolean start) { private LocalServerController(AdempiereServer server, boolean start) {
this.server = server; this.server = server;
stop = new AtomicBoolean(true);
if (start) if (start)
start(); start();
} }
/**
* Submit request to thread pool.
*/
public void start() { public void start() {
stop.set(false);
scheduleFuture = Adempiere.getThreadPoolExecutor().schedule(this, server.getInitialNap() * 1000 + server.getSleepMS(), TimeUnit.MILLISECONDS); scheduleFuture = Adempiere.getThreadPoolExecutor().schedule(this, server.getInitialNap() * 1000 + server.getSleepMS(), TimeUnit.MILLISECONDS);
} }
/**
* Mark stop and interrupt background thread
*/
public void stop() {
stop.set(true);
if (scheduleFuture != null && !scheduleFuture.isDone())
{
scheduleFuture.cancel(true);
}
}
@Override @Override
public void run() { public void run() {
if (stop.get()) {
scheduleFuture = null;
return;
}
if (server.isSleeping()) { if (server.isSleeping()) {
server.run(); server.run();
if (!isInterrupted()) { if (!isInterrupted() && !stop.get()) {
if (server.getSleepMS() != 0) { if (server.getSleepMS() != 0) {
scheduleFuture = Adempiere.getThreadPoolExecutor().schedule(this, server.getSleepMS(), TimeUnit.MILLISECONDS); scheduleFuture = Adempiere.getThreadPoolExecutor().schedule(this, server.getSleepMS(), TimeUnit.MILLISECONDS);
} else {
scheduleFuture = null;
} }
} else {
scheduleFuture = null;
} }
} else { } else {
//server busy, try again after one minute //server busy, try again after one minute
@ -766,18 +793,33 @@ public class AdempiereServerMgr implements ServiceTrackerCustomizer<IServerFacto
} }
} }
/**
* @return {@link AdempiereServer}
*/
public AdempiereServer getServer() { public AdempiereServer getServer() {
return server; return server;
} }
/**
* @return true if server thread is running, false otherwise
*/
public boolean isAlive() { public boolean isAlive() {
return scheduleFuture != null && !scheduleFuture.isDone(); return scheduleFuture != null && !scheduleFuture.isDone() && !isStop();
} }
/**
* @return true if server thread have been interrupted (for e.g, by {@link #stop} call).
*/
public boolean isInterrupted() { public boolean isInterrupted() {
return scheduleFuture != null && scheduleFuture.isCancelled(); return scheduleFuture != null && scheduleFuture.isCancelled();
} }
/**
* @return true if server have been marked as stop
*/
public boolean isStop() {
return stop.get();
}
} }
@Override @Override