Addition of precautionary restart manager.
This commit is contained in:
		@@ -184,6 +184,37 @@ ClanNameTemplate = .*
 | 
			
		||||
CharMaxNumber = 7
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------------------------
 | 
			
		||||
# Precautionary Server Restart
 | 
			
		||||
# ---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# Enable server restart when CPU or memory usage is too high.
 | 
			
		||||
# Default: False
 | 
			
		||||
PrecautionaryRestartEnabled = False
 | 
			
		||||
 | 
			
		||||
# Enable monitoring system CPU usage.
 | 
			
		||||
# Default: True
 | 
			
		||||
PrecautionaryRestartCpu = True
 | 
			
		||||
 | 
			
		||||
# Enable monitoring process memory usage.
 | 
			
		||||
# Default: False
 | 
			
		||||
PrecautionaryRestartMemory = False
 | 
			
		||||
 | 
			
		||||
# Check if sieges are in progress
 | 
			
		||||
# or players are in olympiad, events, instances
 | 
			
		||||
# or have targeted raidbosses.
 | 
			
		||||
# Default: True
 | 
			
		||||
PrecautionaryRestartChecks = True
 | 
			
		||||
 | 
			
		||||
# Percentage of used resources.
 | 
			
		||||
# Default: 95
 | 
			
		||||
PrecautionaryRestartPercentage = 95
 | 
			
		||||
 | 
			
		||||
# Delay in seconds between each check.
 | 
			
		||||
# Default: 60
 | 
			
		||||
PrecautionaryRestartDelay = 60
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------------------------
 | 
			
		||||
# Scheduled Server Restart
 | 
			
		||||
# ---------------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -901,6 +901,12 @@ public class Config
 | 
			
		||||
	public static int SERVER_RESTART_SCHEDULE_COUNTDOWN;
 | 
			
		||||
	public static String[] SERVER_RESTART_SCHEDULE;
 | 
			
		||||
	public static List<Integer> SERVER_RESTART_DAYS;
 | 
			
		||||
	public static boolean PRECAUTIONARY_RESTART_ENABLED;
 | 
			
		||||
	public static boolean PRECAUTIONARY_RESTART_CPU;
 | 
			
		||||
	public static boolean PRECAUTIONARY_RESTART_MEMORY;
 | 
			
		||||
	public static boolean PRECAUTIONARY_RESTART_CHECKS;
 | 
			
		||||
	public static int PRECAUTIONARY_RESTART_PERCENTAGE;
 | 
			
		||||
	public static int PRECAUTIONARY_RESTART_DELAY;
 | 
			
		||||
	
 | 
			
		||||
	// --------------------------------------------------
 | 
			
		||||
	// MMO Settings
 | 
			
		||||
@@ -1481,6 +1487,12 @@ public class Config
 | 
			
		||||
					SERVER_RESTART_DAYS.add(Integer.parseInt(day));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			PRECAUTIONARY_RESTART_ENABLED = serverSettings.getBoolean("PrecautionaryRestartEnabled", false);
 | 
			
		||||
			PRECAUTIONARY_RESTART_CPU = serverSettings.getBoolean("PrecautionaryRestartCpu", true);
 | 
			
		||||
			PRECAUTIONARY_RESTART_MEMORY = serverSettings.getBoolean("PrecautionaryRestartMemory", false);
 | 
			
		||||
			PRECAUTIONARY_RESTART_CHECKS = serverSettings.getBoolean("PrecautionaryRestartChecks", true);
 | 
			
		||||
			PRECAUTIONARY_RESTART_PERCENTAGE = serverSettings.getInt("PrecautionaryRestartPercentage", 95);
 | 
			
		||||
			PRECAUTIONARY_RESTART_DELAY = serverSettings.getInt("PrecautionaryRestartDelay", 60) * 1000;
 | 
			
		||||
			
 | 
			
		||||
			// Hosts and Subnets
 | 
			
		||||
			final IPConfigData ipcd = new IPConfigData();
 | 
			
		||||
 
 | 
			
		||||
@@ -120,6 +120,7 @@ import org.l2jmobius.gameserver.instancemanager.MailManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.MapRegionManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.MercTicketManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.PetitionManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.PremiumManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.PunishmentManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.QuestManager;
 | 
			
		||||
@@ -441,6 +442,10 @@ public class GameServer
 | 
			
		||||
			ServerRestartManager.getInstance();
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (Config.PRECAUTIONARY_RESTART_ENABLED)
 | 
			
		||||
		{
 | 
			
		||||
			PrecautionaryRestartManager.getInstance();
 | 
			
		||||
		}
 | 
			
		||||
		if (Config.DEADLOCK_DETECTOR)
 | 
			
		||||
		{
 | 
			
		||||
			_deadDetectThread = new DeadLockDetector(Duration.ofSeconds(Config.DEADLOCK_CHECK_INTERVAL), () ->
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.GrandBossManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.ItemAuctionManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.PrecautionaryRestartManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.QuestManager;
 | 
			
		||||
import org.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
 | 
			
		||||
import org.l2jmobius.gameserver.model.World;
 | 
			
		||||
@@ -313,6 +314,11 @@ public class Shutdown extends Thread
 | 
			
		||||
			_counterInstance._abort();
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (Config.PRECAUTIONARY_RESTART_ENABLED)
 | 
			
		||||
		{
 | 
			
		||||
			PrecautionaryRestartManager.getInstance().restartEnabled();
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// the main instance should only run for shutdown hook, so we start a new instance
 | 
			
		||||
		_counterInstance = new Shutdown(seconds, restart);
 | 
			
		||||
		_counterInstance.start();
 | 
			
		||||
@@ -328,6 +334,12 @@ public class Shutdown extends Thread
 | 
			
		||||
		if (_counterInstance != null)
 | 
			
		||||
		{
 | 
			
		||||
			_counterInstance._abort();
 | 
			
		||||
			
 | 
			
		||||
			if (Config.PRECAUTIONARY_RESTART_ENABLED)
 | 
			
		||||
			{
 | 
			
		||||
				PrecautionaryRestartManager.getInstance().restartAborted();
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			Broadcast.toAllOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!", false);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,196 @@
 | 
			
		||||
/*
 | 
			
		||||
 * This file is part of the L2J Mobius project.
 | 
			
		||||
 * 
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package org.l2jmobius.gameserver.instancemanager;
 | 
			
		||||
 | 
			
		||||
import java.lang.management.ManagementFactory;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
import javax.management.Attribute;
 | 
			
		||||
import javax.management.AttributeList;
 | 
			
		||||
import javax.management.MBeanServer;
 | 
			
		||||
import javax.management.ObjectName;
 | 
			
		||||
 | 
			
		||||
import org.l2jmobius.Config;
 | 
			
		||||
import org.l2jmobius.commons.concurrent.ThreadPool;
 | 
			
		||||
import org.l2jmobius.gameserver.Shutdown;
 | 
			
		||||
import org.l2jmobius.gameserver.model.World;
 | 
			
		||||
import org.l2jmobius.gameserver.model.WorldObject;
 | 
			
		||||
import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance;
 | 
			
		||||
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
 | 
			
		||||
import org.l2jmobius.gameserver.model.actor.instance.RaidBossInstance;
 | 
			
		||||
import org.l2jmobius.gameserver.model.siege.Castle;
 | 
			
		||||
import org.l2jmobius.gameserver.model.siege.Fort;
 | 
			
		||||
import org.l2jmobius.gameserver.util.Broadcast;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Mobius
 | 
			
		||||
 */
 | 
			
		||||
public class PrecautionaryRestartManager
 | 
			
		||||
{
 | 
			
		||||
	private static final Logger LOGGER = Logger.getLogger(PrecautionaryRestartManager.class.getName());
 | 
			
		||||
	
 | 
			
		||||
	private static final String SYSTEM_CPU_LOAD_VAR = "SystemCpuLoad";
 | 
			
		||||
	private static final String PROCESS_CPU_LOAD_VAR = "ProcessCpuLoad";
 | 
			
		||||
	
 | 
			
		||||
	private static boolean _restarting = false;
 | 
			
		||||
	
 | 
			
		||||
	protected PrecautionaryRestartManager()
 | 
			
		||||
	{
 | 
			
		||||
		ThreadPool.scheduleAtFixedRate(() ->
 | 
			
		||||
		{
 | 
			
		||||
			if (_restarting)
 | 
			
		||||
			{
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (Config.PRECAUTIONARY_RESTART_CPU && (getCpuLoad(SYSTEM_CPU_LOAD_VAR) > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
 | 
			
		||||
			{
 | 
			
		||||
				if (serverBizzy())
 | 
			
		||||
				{
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				LOGGER.info("PrecautionaryRestartManager: CPU usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
 | 
			
		||||
				LOGGER.info("PrecautionaryRestartManager: Server is using " + getCpuLoad(PROCESS_CPU_LOAD_VAR) + "%.");
 | 
			
		||||
				Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
 | 
			
		||||
				Shutdown.getInstance().startShutdown(null, 600, true);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (Config.PRECAUTIONARY_RESTART_MEMORY && (getProcessRamLoad() > Config.PRECAUTIONARY_RESTART_PERCENTAGE))
 | 
			
		||||
			{
 | 
			
		||||
				if (serverBizzy())
 | 
			
		||||
				{
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				LOGGER.info("PrecautionaryRestartManager: Memory usage over " + Config.PRECAUTIONARY_RESTART_PERCENTAGE + "%.");
 | 
			
		||||
				Broadcast.toAllOnlinePlayers("Server will restart in 10 minutes.", false);
 | 
			
		||||
				Shutdown.getInstance().startShutdown(null, 600, true);
 | 
			
		||||
			}
 | 
			
		||||
		}, Config.PRECAUTIONARY_RESTART_DELAY, Config.PRECAUTIONARY_RESTART_DELAY);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private static double getCpuLoad(String var)
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
 | 
			
		||||
			final ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
 | 
			
		||||
			final AttributeList list = mbs.getAttributes(name, new String[]
 | 
			
		||||
			{
 | 
			
		||||
				var
 | 
			
		||||
			});
 | 
			
		||||
			
 | 
			
		||||
			if (list.isEmpty())
 | 
			
		||||
			{
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			final Attribute att = (Attribute) list.get(0);
 | 
			
		||||
			final Double value = (Double) att.getValue();
 | 
			
		||||
			if (value == -1)
 | 
			
		||||
			{
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			return (value * 1000) / 10d;
 | 
			
		||||
		}
 | 
			
		||||
		catch (Exception e)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private static double getProcessRamLoad()
 | 
			
		||||
	{
 | 
			
		||||
		final Runtime runTime = Runtime.getRuntime();
 | 
			
		||||
		final long totalMemory = runTime.maxMemory();
 | 
			
		||||
		final long usedMemory = totalMemory - ((totalMemory - runTime.totalMemory()) + runTime.freeMemory());
 | 
			
		||||
		return (usedMemory * 100) / totalMemory;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private boolean serverBizzy()
 | 
			
		||||
	{
 | 
			
		||||
		for (Castle castle : CastleManager.getInstance().getCastles())
 | 
			
		||||
		{
 | 
			
		||||
			if ((castle != null) && castle.getSiege().isInProgress())
 | 
			
		||||
			{
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		for (Fort fort : FortManager.getInstance().getForts())
 | 
			
		||||
		{
 | 
			
		||||
			if ((fort != null) && fort.getSiege().isInProgress())
 | 
			
		||||
			{
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		for (PlayerInstance player : World.getInstance().getPlayers())
 | 
			
		||||
		{
 | 
			
		||||
			if ((player == null) || player.isInOfflineMode())
 | 
			
		||||
			{
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (player.isInOlympiadMode())
 | 
			
		||||
			{
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (player.isOnEvent())
 | 
			
		||||
			{
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (player.getInstanceId() > 0)
 | 
			
		||||
			{
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			final WorldObject target = player.getTarget();
 | 
			
		||||
			if ((target instanceof RaidBossInstance) || (target instanceof GrandBossInstance))
 | 
			
		||||
			{
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void restartEnabled()
 | 
			
		||||
	{
 | 
			
		||||
		_restarting = true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void restartAborted()
 | 
			
		||||
	{
 | 
			
		||||
		_restarting = false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static PrecautionaryRestartManager getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		return SingletonHolder.INSTANCE;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private static class SingletonHolder
 | 
			
		||||
	{
 | 
			
		||||
		protected static final PrecautionaryRestartManager INSTANCE = new PrecautionaryRestartManager();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user