Added new start/stop hooks to server. These are read differently depending on if the server is reloaded or reset/shutdown. OBS: If you have already implemented your own version of AT_STARTSTOP_MODULE, you need to add stubs for new hooks. You can find the required hooks in gamesrc/conf/examples/at_startstop.py.

gamesrc/conf/examples
This commit is contained in:
Griatch 2012-10-28 22:02:22 +01:00
parent b15d1fa683
commit 92f6b06626
4 changed files with 90 additions and 38 deletions

View file

@ -252,7 +252,7 @@ def del_pid(pidfile):
if os.path.exists(pidfile): if os.path.exists(pidfile):
os.remove(pidfile) os.remove(pidfile)
def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART, restart=True): def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART, restart="reload"):
""" """
Send a kill signal to a process based on PID. A customized success/error Send a kill signal to a process based on PID. A customized success/error
message will be returned. If clean=True, the system will attempt to manually message will be returned. If clean=True, the system will attempt to manually
@ -321,17 +321,17 @@ def run_menu():
if os.name == 'nt': if os.name == 'nt':
print "This operation is not supported under Windows. Log into the game to restart/reload the server." print "This operation is not supported under Windows. Log into the game to restart/reload the server."
return return
kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % "Server") kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % "Server", restart="reload")
elif inp == 6: elif inp == 6:
if os.name == 'nt': if os.name == 'nt':
print "This operation is not supported under Windows." print "This operation is not supported under Windows."
return return
kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped if in daemon mode).", errmsg % "Portal") kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped if in daemon mode).", errmsg % "Portal", restart=True)
elif inp == 7: elif inp == 7:
kill(SERVER_PIDFILE, SIG, "Stopped Portal.", errmsg % "Portal", PORTAL_RESTART, restart=False) kill(SERVER_PIDFILE, SIG, "Stopped Portal.", errmsg % "Portal", PORTAL_RESTART, restart=False)
kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart=False) kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart="shutdown")
elif inp == 8: elif inp == 8:
kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart=False) kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart="shutdown")
elif inp == 9: elif inp == 9:
kill(SERVER_PIDFILE, SIG, "Stopped Portal.", errmsg % "Portal", PORTAL_RESTART, restart=False) kill(SERVER_PIDFILE, SIG, "Stopped Portal.", errmsg % "Portal", PORTAL_RESTART, restart=False)
return return
@ -379,7 +379,7 @@ def handle_args(options, mode, service):
print "Restarting from command line is not supported under Windows. Log into the game to restart." print "Restarting from command line is not supported under Windows. Log into the game to restart."
return return
if service == 'server': if service == 'server':
kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % 'Server') kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % 'Server', restart="reload")
elif service == 'portal': elif service == 'portal':
print """ print """
Note: Portal usually don't need to be reloaded unless you are debugging in interactive mode. Note: Portal usually don't need to be reloaded unless you are debugging in interactive mode.
@ -389,17 +389,17 @@ def handle_args(options, mode, service):
kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped, if it was in daemon mode).", errmsg % 'Portal', PORTAL_RESTART) kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped, if it was in daemon mode).", errmsg % 'Portal', PORTAL_RESTART)
else: # all else: # all
# default mode, only restart server # default mode, only restart server
kill(SERVER_PIDFILE, SIG, "Server reload.", errmsg % 'Server') kill(SERVER_PIDFILE, SIG, "Server reload.", errmsg % 'Server', restart="reload")
elif mode == 'stop': elif mode == 'stop':
# stop processes, avoiding reload # stop processes, avoiding reload
if service == 'server': if service == 'server':
kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart=False) kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart="shutdown")
elif service == 'portal': elif service == 'portal':
kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART, restart=False) kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART, restart=False)
else: else:
kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART, restart=False) kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART, restart=False)
kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart=False) kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart="shutdown")
return None return None
def error_check_python_modules(): def error_check_python_modules():

View file

@ -19,19 +19,48 @@ The module should define at least these global functions:
at_server_start() at_server_start()
at_server_stop() at_server_stop()
at_server_reload_start()
at_server_reload_stop()
at_server_cold_start()
at_server_cold_stop()
""" """
def at_server_start(): def at_server_start():
""" """
This is called every time the server starts up (also after a This is called every time the server starts up, regardless of
reload or reset). how it was shut down.
""" """
pass pass
def at_server_stop(): def at_server_stop():
""" """
This is called just before a server is shut down, reloaded or This is called just before a server is shut down, regardless
reset. of it is fore a reload, reset or shutdown.
"""
pass
def at_server_reload_start():
"""
This is called only when server starts back up after a reload.
"""
pass
def at_server_reload_stop():
"""
This is called only time the server stops before a reload.
"""
pass
def at_server_cold_start():
"""
This is called only when the server starts "cold", i.e. after a
shutdown or a reset.
"""
pass
def at_server_cold_stop():
"""
This is called only when the server goes down due to a shutdown or reset.
""" """
pass pass

View file

@ -74,22 +74,21 @@ if os.name == 'nt':
# Functions # Functions
def set_restart_mode(restart_file, flag=True): def set_restart_mode(restart_file, flag="reload"):
""" """
This sets a flag file for the restart mode. This sets a flag file for the restart mode.
""" """
f = open(restart_file, 'w') with open(restart_file, 'w') as f:
f.write(str(flag)) f.write(str(flag))
f.close()
def get_restart_mode(restart_file): def get_restart_mode(restart_file):
""" """
Parse the server/portal restart status Parse the server/portal restart status
""" """
if os.path.exists(restart_file): if os.path.exists(restart_file):
flag = open(restart_file, 'r').read() with open(restart_file, 'r') as f:
return flag == "True" return f.read()
return False return "shutdown"
def get_pid(pidfile): def get_pid(pidfile):
""" """
@ -98,7 +97,7 @@ def get_pid(pidfile):
""" """
pid = None pid = None
if os.path.exists(pidfile): if os.path.exists(pidfile):
f = open(pidfile, 'r') with open(pidfile, 'r') as f:
pid = f.read() pid = f.read()
return pid return pid
@ -165,7 +164,7 @@ def start_services(server_argv, portal_argv):
if portal_argv: if portal_argv:
try: try:
if get_restart_mode(PORTAL_RESTART): if get_restart_mode(PORTAL_RESTART) == "True":
# start portal as interactive, reloadable thread # start portal as interactive, reloadable thread
PORTAL = thread.start_new_thread(portal_waiter, (processes, )) PORTAL = thread.start_new_thread(portal_waiter, (processes, ))
else: else:
@ -185,13 +184,13 @@ def start_services(server_argv, portal_argv):
message, rc = processes.get() message, rc = processes.get()
# restart only if process stopped cleanly # restart only if process stopped cleanly
if message == "server_stopped" and int(rc) == 0 and get_restart_mode(SERVER_RESTART): if message == "server_stopped" and int(rc) == 0 and get_restart_mode(SERVER_RESTART) in ("True", "reload", "reset"):
print "Evennia Server stopped. Restarting ..." print "Evennia Server stopped. Restarting ..."
SERVER = thread.start_new_thread(server_waiter, (processes, )) SERVER = thread.start_new_thread(server_waiter, (processes, ))
continue continue
# normally the portal is not reloaded since it's run as a daemon. # normally the portal is not reloaded since it's run as a daemon.
if message == "portal_stopped" and int(rc) == 0 and get_restart_mode(PORTAL_RESTART): if message == "portal_stopped" and int(rc) == 0 and get_restart_mode(PORTAL_RESTART) == "True":
print "Evennia Portal stopped in interactive mode. Restarting ..." print "Evennia Portal stopped in interactive mode. Restarting ..."
PORTAL = thread.start_new_thread(portal_waiter, (processes, )) PORTAL = thread.start_new_thread(portal_waiter, (processes, ))
continue continue
@ -261,7 +260,7 @@ def main():
if options.noserver: if options.noserver:
server_argv = None server_argv = None
else: else:
set_restart_mode(SERVER_RESTART, True) set_restart_mode(SERVER_RESTART, "shutdown")
if options.iserver: if options.iserver:
# don't log to server logfile # don't log to server logfile
del server_argv[2] del server_argv[2]

View file

@ -39,7 +39,7 @@ if os.name == 'nt':
# a file with a flag telling the server to restart after shutdown or not. # a file with a flag telling the server to restart after shutdown or not.
SERVER_RESTART = os.path.join(settings.GAME_DIR, 'server.restart') SERVER_RESTART = os.path.join(settings.GAME_DIR, 'server.restart')
# module containing hook methods # module containing hook methods called during start_stop
SERVER_STARTSTOP_MODULE = mod_import(settings.AT_SERVER_STARTSTOP_MODULE) SERVER_STARTSTOP_MODULE = mod_import(settings.AT_SERVER_STARTSTOP_MODULE)
# module containing plugin services # module containing plugin services
@ -197,8 +197,16 @@ class Evennia(object):
[(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()] [(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()]
[(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()] [(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()]
# call server hook.
if SERVER_STARTSTOP_MODULE: if SERVER_STARTSTOP_MODULE:
# call correct server hook based on start file value
with open(SERVER_RESTART, 'r') as f:
mode = f.read()
if mode in ('True', 'reload'):
# True was the old reload flag, kept for compatibilty
SERVER_STARTSTOP_MODULE.at_server_reload_start()
elif mode in ('reset', 'shutdown'):
SERVER_STARTSTOP_MODULE.at_server_cold_start()
# always call this regardless of start type
SERVER_STARTSTOP_MODULE.at_server_start() SERVER_STARTSTOP_MODULE.at_server_start()
def set_restart_mode(self, mode=None): def set_restart_mode(self, mode=None):
@ -212,19 +220,28 @@ class Evennia(object):
returned so the server knows which more it's in. returned so the server knows which more it's in.
""" """
if mode == None: if mode == None:
f = open(SERVER_RESTART, 'r') with open(SERVER_RESTART, 'r') as f:
if os.path.exists(SERVER_RESTART) and 'True' == f.read(): # mode is either shutdown, reset or reload
mode = 'reload' mode = f.read()
else: else:
mode = 'shutdown' with open(SERVER_RESTART, 'w') as f:
f.close() f.write(str(mode))
else:
restart = mode in ('reload', 'reset')
f = open(SERVER_RESTART, 'w')
f.write(str(restart))
f.close()
return mode return mode
#if mode == None:
# 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')
# f.write(str(restart))
# f.close()
#return mode
@defer.inlineCallbacks @defer.inlineCallbacks
def shutdown(self, mode=None, _reactor_stopping=False): def shutdown(self, mode=None, _reactor_stopping=False):
""" """
@ -257,6 +274,10 @@ class Evennia(object):
yield [(s.typeclass, s.pause(), s.at_server_reload()) for s in ScriptDB.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() yield self.sessions.all_sessions_portal_sync()
ServerConfig.objects.conf("server_restart_mode", "reload") ServerConfig.objects.conf("server_restart_mode", "reload")
if SERVER_STARTSTOP_MODULE:
SERVER_STARTSTOP_MODULE.at_server_reload_stop()
else: else:
if mode == 'reset': if mode == 'reset':
# don't call disconnect hooks on reset # don't call disconnect hooks on reset
@ -270,6 +291,9 @@ class Evennia(object):
ServerConfig.objects.conf("server_restart_mode", "reset") ServerConfig.objects.conf("server_restart_mode", "reset")
if SERVER_STARTSTOP_MODULE:
SERVER_STARTSTOP_MODULE.at_server_cold_stop()
if SERVER_STARTSTOP_MODULE: if SERVER_STARTSTOP_MODULE:
SERVER_STARTSTOP_MODULE.at_server_stop() SERVER_STARTSTOP_MODULE.at_server_stop()
# if _reactor_stopping is true, reactor does not need to be stopped again. # if _reactor_stopping is true, reactor does not need to be stopped again.