Updated the reload and shutdown mecanism to avoid a loop when shutting down from inside the game. Made sure to have server sync correctly with portal at @reload (some session info were lost before). Some other cleanups.

This commit is contained in:
Griatch 2012-05-01 14:19:54 +02:00
parent e82515f8cb
commit 94477b8340
8 changed files with 171 additions and 118 deletions

View file

@ -17,8 +17,7 @@ if os.name == 'nt':
os.path.dirname(os.path.abspath(__file__)))))
from twisted.application import internet, service
from twisted.internet import protocol, reactor, defer
from twisted.web import server, static
from twisted.internet import reactor, defer
import django
from django.db import connection
from django.conf import settings
@ -106,7 +105,7 @@ class Evennia(object):
# set a callback if the server is killed abruptly,
# by Ctrl-C, reboot etc.
reactor.addSystemEventTrigger('before', 'shutdown', self.shutdown, _abrupt=True)
reactor.addSystemEventTrigger('before', 'shutdown', self.shutdown, _reactor_stopping=True)
self.game_running = True
@ -133,6 +132,7 @@ class Evennia(object):
"""
This attempts to run the initial_setup script of the server.
It returns if this is not the first time the server starts.
Once finished the last_initial_setup_step is set to -1.
"""
last_initial_setup_step = ServerConfig.objects.conf('last_initial_setup_step')
if not last_initial_setup_step:
@ -184,10 +184,12 @@ class Evennia(object):
returned so the server knows which more it's in.
"""
if mode == None:
if os.path.exists(SERVER_RESTART) and 'True' == open(SERVER_RESTART, 'r').read():
f = open(SERVER_RESTART, 'r')
if os.path.exists(SERVER_RESTART) and 'True' == f.read():
mode = 'reload'
else:
mode = 'shutdown'
f.close()
else:
restart = mode in ('reload', 'reset')
f = open(SERVER_RESTART, 'w')
@ -195,7 +197,8 @@ class Evennia(object):
f.close()
return mode
def shutdown(self, mode=None, _abrupt=False):
@defer.inlineCallbacks
def shutdown(self, mode=None, _reactor_stopping=False):
"""
Shuts down the server from inside it.
@ -204,11 +207,15 @@ class Evennia(object):
'reset' - server restarts, non-persistent scripts stopped, at_shutdown hooks called.
'shutdown' - like reset, but server will not auto-restart.
None - keep currently set flag from flag file.
_abrupt - this is set if server is stopped by a kill command,
in which case the reactor is dead anyway.
_reactor_stopping - this is set if server is stopped by a kill command OR this method was already called
once - in both cases the reactor is dead/stopping already.
"""
mode = self.set_restart_mode(mode)
if _reactor_stopping and hasattr(self, "shutdown_complete"):
# this means we have already passed through this method once; we don't need
# to run the shutdown procedure again.
defer.returnValue(None)
mode = self.set_restart_mode(mode)
# call shutdown hooks on all cached objects
from src.objects.models import ObjectDB
@ -217,31 +224,34 @@ class Evennia(object):
if mode == 'reload':
# call restart hooks
[(o.typeclass, o.at_server_reload()) for o in ObjectDB.get_all_cached_instances()]
[(p.typeclass, p.at_server_reload()) for p in PlayerDB.get_all_cached_instances()]
[(s.typeclass, s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()]
yield [(o.typeclass, o.at_server_reload()) for o in ObjectDB.get_all_cached_instances()]
yield [(p.typeclass, p.at_server_reload()) for p in PlayerDB.get_all_cached_instances()]
yield [(s.typeclass, s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()]
yield self.sessions.all_sessions_portal_sync()
ServerConfig.objects.conf("server_restart_mode", "reload")
else:
if mode == 'reset':
# don't call disconnect hooks on reset
[(o.typeclass, o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()]
yield [(o.typeclass, o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()]
yield self.all_sessions_portal_sync()
else: # shutdown
[(o.typeclass, o.at_disconnect(), o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()]
yield [(o.typeclass, o.at_disconnect(), o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()]
[(p.typeclass, p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()]
[(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()]
yield [(p.typeclass, p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()]
yield [(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()]
ServerConfig.objects.conf("server_restart_mode", "reset")
if not _abrupt:
if SERVER_HOOK_MODULE:
SERVER_HOOK_MODULE.at_server_stop()
reactor.callLater(0, reactor.stop)
if SERVER_HOOK_MODULE:
SERVER_HOOK_MODULE.at_server_stop()
# if _reactor_stopping is true, reactor does not need to be stopped again.
if os.name == 'nt' and os.path.exists(SERVER_PIDFILE):
# for Windows we need to remove pid files manually
os.remove(SERVER_PIDFILE)
if not _reactor_stopping:
# this will also send a reactor.stop signal, so we set a flag to avoid loops.
self.shutdown_complete = True
reactor.callLater(0, reactor.stop)
#------------------------------------------------------------
#