Prevent some shutdown exceptions - closes #136

This commit is contained in:
Luck 2017-01-19 18:56:04 +00:00
parent 02b88a8357
commit 01ac5382ea
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
6 changed files with 77 additions and 20 deletions

View File

@ -116,7 +116,7 @@ class BukkitListener extends AbstractListener implements Listener {
final Player player = e.getPlayer(); final Player player = e.getPlayer();
// Remove the custom permissible // Remove the custom permissible
Injector.unInject(player, true); Injector.unInject(player, true, true);
// Handle auto op // Handle auto op
if (plugin.getConfiguration().isAutoOp()) { if (plugin.getConfiguration().isAutoOp()) {

View File

@ -82,6 +82,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -91,14 +92,19 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Getter @Getter
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private Set<UUID> ignoringLogs; private Set<UUID> ignoringLogs;
private Set<Runnable> shutdownHooks;
private Executor syncExecutor; private Executor syncExecutor;
private Executor asyncExecutor; private Executor asyncExecutor;
private Executor asyncBukkitExecutor;
private ExecutorService asyncLpExecutor;
private VaultHook vaultHook = null; private VaultHook vaultHook = null;
private LPConfiguration configuration; private LPConfiguration configuration;
private UserManager userManager; private UserManager userManager;
@ -126,16 +132,19 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
// Used whilst the server is still starting // Used whilst the plugin is enabling / disabling / disabled
asyncExecutor = Executors.newCachedThreadPool(); asyncLpExecutor = Executors.newCachedThreadPool();
asyncBukkitExecutor = r -> getServer().getScheduler().runTaskAsynchronously(this, r);
asyncExecutor = asyncLpExecutor;
syncExecutor = r -> getServer().getScheduler().runTask(this, r); syncExecutor = r -> getServer().getScheduler().runTask(this, r);
Executor bukkitAsyncExecutor = r -> getServer().getScheduler().runTaskAsynchronously(this, r);
log = LogFactory.wrap(getLogger()); log = LogFactory.wrap(getLogger());
ignoringLogs = ConcurrentHashMap.newKeySet(); ignoringLogs = ConcurrentHashMap.newKeySet();
debugHandler = new DebugHandler(bukkitAsyncExecutor, getVersion()); shutdownHooks = Collections.synchronizedSet(new HashSet<>());
debugHandler = new DebugHandler(asyncBukkitExecutor, getVersion());
senderFactory = new BukkitSenderFactory(this); senderFactory = new BukkitSenderFactory(this);
permissionCache = new PermissionCache(bukkitAsyncExecutor); permissionCache = new PermissionCache(asyncBukkitExecutor);
getLog().info("Loading configuration..."); getLog().info("Loading configuration...");
configuration = new BukkitConfig(this); configuration = new BukkitConfig(this);
@ -270,7 +279,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// replace the temporary executor when the Bukkit one starts // replace the temporary executor when the Bukkit one starts
getServer().getScheduler().runTaskAsynchronously(this, () -> { getServer().getScheduler().runTaskAsynchronously(this, () -> {
asyncExecutor = bukkitAsyncExecutor; asyncExecutor = asyncBukkitExecutor;
}); });
// Load any online users (in the case of a reload) // Load any online users (in the case of a reload)
@ -297,14 +306,19 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
// Switch back to the LP executor, the bukkit one won't allow new tasks
asyncExecutor = asyncLpExecutor;
started = false; started = false;
shutdownHooks.forEach(Runnable::run);
defaultsProvider.close(); defaultsProvider.close();
permissionCache.setShutdown(true); permissionCache.setShutdown(true);
debugHandler.setShutdown(true); debugHandler.setShutdown(true);
for (Player player : getServer().getOnlinePlayers()) { for (Player player : getServer().getOnlinePlayers()) {
Injector.unInject(player, false); Injector.unInject(player, false, false);
if (getConfiguration().isAutoOp()) { if (getConfiguration().isAutoOp()) {
player.setOp(false); player.setOp(false);
} }
@ -332,14 +346,20 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
vaultHook.unhook(this); vaultHook.unhook(this);
} }
// wait for executor
asyncLpExecutor.shutdown();
try {
asyncLpExecutor.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Bukkit will do this again when #onDisable completes, but we do it early to prevent NPEs elsewhere. // Bukkit will do this again when #onDisable completes, but we do it early to prevent NPEs elsewhere.
getServer().getScheduler().cancelTasks(this); getServer().getScheduler().cancelTasks(this);
HandlerList.unregisterAll(this); HandlerList.unregisterAll(this);
// Null everything // Null everything
ignoringLogs = null; ignoringLogs = null;
syncExecutor = null;
asyncExecutor = null;
vaultHook = null; vaultHook = null;
configuration = null; configuration = null;
userManager = null; userManager = null;
@ -615,6 +635,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return getServer().getPluginManager().isPluginEnabled(name); return getServer().getPluginManager().isPluginEnabled(name);
} }
@Override
public void addShutdownHook(Runnable r) {
shutdownHooks.add(r);
}
private void registerPermissions(PermissionDefault def) { private void registerPermissions(PermissionDefault def) {
PluginManager pm = getServer().getPluginManager(); PluginManager pm = getServer().getPluginManager();

View File

@ -88,13 +88,16 @@ public class Injector {
} }
} }
public static boolean unInject(Player player, boolean dummy) { public static boolean unInject(Player player, boolean dummy, boolean unsubscribe) {
try { try {
PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_FIELD.get(player); PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_FIELD.get(player);
if (permissible instanceof LPPermissible) { if (permissible instanceof LPPermissible) {
permissible.clearPermissions(); permissible.clearPermissions();
((LPPermissible) permissible).unsubscribeFromAllAsync();
if (unsubscribe) {
((LPPermissible) permissible).unsubscribeFromAllAsync();
}
if (dummy) { if (dummy) {
HUMAN_ENTITY_FIELD.set(player, new DummyPermissibleBase()); HUMAN_ENTITY_FIELD.set(player, new DummyPermissibleBase());

View File

@ -68,6 +68,7 @@ import net.md_5.bungee.api.plugin.Plugin;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -80,6 +81,7 @@ import java.util.stream.Collectors;
@Getter @Getter
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet(); private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private final Set<Runnable> shutdownHooks = Collections.synchronizedSet(new HashSet<>());
private Executor executor; private Executor executor;
private LPConfiguration configuration; private LPConfiguration configuration;
private UserManager userManager; private UserManager userManager;
@ -201,6 +203,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
shutdownHooks.forEach(Runnable::run);
getLog().info("Closing datastore..."); getLog().info("Closing datastore...");
storage.shutdown(); storage.shutdown();
@ -211,6 +215,9 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
getLog().info("Unregistering API..."); getLog().info("Unregistering API...");
ApiHandler.unregisterProvider(); ApiHandler.unregisterProvider();
getProxy().getScheduler().cancel(this);
getProxy().getPluginManager().unregisterListeners(this);
} }
@Override @Override
@ -344,9 +351,12 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
@Override @Override
public boolean isPluginLoaded(String name) { public boolean isPluginLoaded(String name) {
return getProxy().getPluginManager().getPlugins().stream() return getProxy().getPluginManager().getPlugins().stream()
.filter(p -> p.getDescription().getName().equalsIgnoreCase(name)) .anyMatch(p -> p.getDescription().getName().equalsIgnoreCase(name));
.findAny() }
.isPresent();
@Override
public void addShutdownHook(Runnable r) {
shutdownHooks.add(r);
} }
@Override @Override

View File

@ -387,6 +387,12 @@ public interface LuckPermsPlugin {
*/ */
BufferedRequest<Void> getUpdateTaskBuffer(); BufferedRequest<Void> getUpdateTaskBuffer();
/**
* Adds a runnable to be called when the plugin disables
* @param r the runnable to run
*/
void addShutdownHook(Runnable r);
/** /**
* Called at the end of the sync task. * Called at the end of the sync task.
*/ */

View File

@ -86,6 +86,7 @@ import org.spongepowered.api.scheduler.AsynchronousExecutor;
import org.spongepowered.api.scheduler.Scheduler; import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.scheduler.SpongeExecutorService; import org.spongepowered.api.scheduler.SpongeExecutorService;
import org.spongepowered.api.scheduler.SynchronousExecutor; import org.spongepowered.api.scheduler.SynchronousExecutor;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.service.permission.PermissionDescription; import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService; import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject; import org.spongepowered.api.service.permission.Subject;
@ -96,6 +97,7 @@ import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -111,6 +113,7 @@ import java.util.stream.StreamSupport;
public class LPSpongePlugin implements LuckPermsPlugin { public class LPSpongePlugin implements LuckPermsPlugin {
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet(); private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private final Set<Runnable> shutdownHooks = Collections.synchronizedSet(new HashSet<>());
@Inject @Inject
private Logger logger; private Logger logger;
@ -251,18 +254,23 @@ public class LPSpongePlugin implements LuckPermsPlugin {
// schedule update tasks // schedule update tasks
int mins = getConfiguration().getSyncTime(); int mins = getConfiguration().getSyncTime();
if (mins > 0) { if (mins > 0) {
scheduler.createTaskBuilder().async().interval(mins, TimeUnit.MINUTES).execute(new UpdateTask(this)) Task t = scheduler.createTaskBuilder().async().interval(mins, TimeUnit.MINUTES).execute(new UpdateTask(this))
.submit(LPSpongePlugin.this); .submit(LPSpongePlugin.this);
addShutdownHook(t::cancel);
} }
// run an update instantly. // run an update instantly.
updateTaskBuffer.requestDirectly(); updateTaskBuffer.requestDirectly();
// register tasks // register tasks
scheduler.createTaskBuilder().async().intervalTicks(60L).execute(new ExpireTemporaryTask(this)).submit(this); Task t2 = scheduler.createTaskBuilder().async().intervalTicks(60L).execute(new ExpireTemporaryTask(this)).submit(this);
scheduler.createTaskBuilder().async().intervalTicks(2400L).execute(new CacheHousekeepingTask(this)).submit(this); Task t3 = scheduler.createTaskBuilder().async().intervalTicks(2400L).execute(new CacheHousekeepingTask(this)).submit(this);
scheduler.createTaskBuilder().async().intervalTicks(2400L).execute(new ServiceCacheHousekeepingTask(service)).submit(this); Task t4 = scheduler.createTaskBuilder().async().intervalTicks(2400L).execute(new ServiceCacheHousekeepingTask(service)).submit(this);
scheduler.createTaskBuilder().async().intervalTicks(2400L).execute(() -> userManager.performCleanup()).submit(this); Task t5 = scheduler.createTaskBuilder().async().intervalTicks(2400L).execute(() -> userManager.performCleanup()).submit(this);
addShutdownHook(t2::cancel);
addShutdownHook(t3::cancel);
addShutdownHook(t4::cancel);
addShutdownHook(t5::cancel);
getLog().info("Successfully loaded."); getLog().info("Successfully loaded.");
} }
@ -441,6 +449,11 @@ public class LPSpongePlugin implements LuckPermsPlugin {
return game.getPluginManager().isLoaded(name); return game.getPluginManager().isLoaded(name);
} }
@Override
public void addShutdownHook(Runnable r) {
shutdownHooks.add(r);
}
@Override @Override
public void doAsync(Runnable r) { public void doAsync(Runnable r) {
scheduler.createTaskBuilder().async().execute(r).submit(this); scheduler.createTaskBuilder().async().execute(r).submit(this);