mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 01:36:32 +01:00
Make pid handling more stable, also internally
This commit is contained in:
parent
c6eca6bf03
commit
c0fe8a92ee
5 changed files with 30 additions and 34 deletions
|
|
@ -4,6 +4,7 @@ Portal. This module sets up the Client-side communication.
|
|||
|
||||
"""
|
||||
|
||||
import os
|
||||
from evennia.server.portal import amp
|
||||
from twisted.internet import protocol
|
||||
from evennia.utils import logger
|
||||
|
|
@ -105,7 +106,8 @@ class AMPServerClientProtocol(amp.AMPMultiConnectionProtocol):
|
|||
super(AMPServerClientProtocol, self).connectionMade()
|
||||
# first thing we do is to request the Portal to sync all sessions
|
||||
# back with the Server side. We also need the startup mode (reload, reset, shutdown)
|
||||
self.send_AdminServer2Portal(amp.DUMMYSESSION, operation=amp.PSYNC, info_dict=info_dict)
|
||||
self.send_AdminServer2Portal(
|
||||
amp.DUMMYSESSION, operation=amp.PSYNC, spid=os.getpid(), info_dict=info_dict)
|
||||
|
||||
def data_to_portal(self, command, sessid, **kwargs):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -679,16 +679,14 @@ def query_status(callback=None):
|
|||
callback(response)
|
||||
else:
|
||||
pstatus, sstatus, ppid, spid, pinfo, sinfo = _parse_status(response)
|
||||
# note - the server reports its pid, but this is likely to be a
|
||||
# thread and can't be relied on, so we use the pid file instead
|
||||
print("Portal: {} (pid {})\nServer: {} (pid {})".format(
|
||||
wmap[pstatus], get_pid(PORTAL_PIDFILE),
|
||||
wmap[sstatus], get_pid(SERVER_PIDFILE)))
|
||||
print("Evennia Portal: {}{}\n Server: {}{}".format(
|
||||
wmap[pstatus], " (pid {})".format(get_pid(PORTAL_PIDFILE, ppid)) if pstatus else "",
|
||||
wmap[sstatus], " (pid {})".format(get_pid(SERVER_PIDFILE, spid)) if sstatus else ""))
|
||||
_reactor_stop()
|
||||
|
||||
def _errback(fail):
|
||||
pstatus, sstatus = False, False
|
||||
print("Portal: {}\nServer: {}".format(wmap[pstatus], wmap[sstatus]))
|
||||
print("Portal: {}\nServer: {}".format(wmap[pstatus], wmap[sstatus]))
|
||||
_reactor_stop()
|
||||
|
||||
send_instruction(PSTATUS, None, _callback, _errback)
|
||||
|
|
@ -1355,22 +1353,23 @@ def getenv():
|
|||
return env
|
||||
|
||||
|
||||
def get_pid(pidfile):
|
||||
def get_pid(pidfile, default=None):
|
||||
"""
|
||||
Get the PID (Process ID) by trying to access an PID file.
|
||||
|
||||
Args:
|
||||
pidfile (str): The path of the pid file.
|
||||
default (int, optional): What to return if file does not exist.
|
||||
|
||||
Returns:
|
||||
pid (str or None): The process id.
|
||||
pid (str): The process id or `default`.
|
||||
|
||||
"""
|
||||
if os.path.exists(pidfile):
|
||||
with open(pidfile, 'r') as f:
|
||||
pid = f.read()
|
||||
return pid
|
||||
return None
|
||||
return default
|
||||
|
||||
|
||||
def del_pid(pidfile):
|
||||
|
|
@ -1418,7 +1417,7 @@ def kill(pidfile, component='Server', callback=None, errback=None, killsignal=SI
|
|||
# We must catch and ignore the interrupt sent.
|
||||
pass
|
||||
else:
|
||||
# Linux can send the SIGINT signal directly
|
||||
# Linux/Unix can send the SIGINT signal directly
|
||||
# to the specified PID.
|
||||
os.kill(int(pid), killsignal)
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ class AMPServerFactory(protocol.ServerFactory):
|
|||
self.protocol = AMPServerProtocol
|
||||
self.broadcasts = []
|
||||
self.server_connection = None
|
||||
self.server_info_dict = None
|
||||
self.launcher_connection = None
|
||||
self.disconnect_callbacks = {}
|
||||
self.server_connect_callbacks = []
|
||||
|
|
@ -89,7 +88,7 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
super(AMPServerProtocol, self).connectionLost(reason)
|
||||
if self.factory.server_connection == self:
|
||||
self.factory.server_connection = None
|
||||
self.factory.server_info_dict = None
|
||||
self.factory.portal.server_info_dict = {}
|
||||
if self.factory.launcher_connection == self:
|
||||
self.factory.launcher_connection = None
|
||||
|
||||
|
|
@ -112,7 +111,7 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
server_connected = bool(self.factory.server_connection and
|
||||
self.factory.server_connection.transport.connected)
|
||||
portal_info_dict = self.factory.portal.get_info_dict()
|
||||
server_info_dict = self.factory.server_info_dict
|
||||
server_info_dict = self.factory.portal.server_info_dict
|
||||
server_pid = self.factory.portal.server_process_id
|
||||
portal_pid = os.getpid()
|
||||
return (True, server_connected, portal_pid, server_pid, portal_info_dict, server_info_dict)
|
||||
|
|
@ -151,7 +150,11 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
|
||||
"""
|
||||
# start the Server
|
||||
process = None
|
||||
with open(settings.SERVER_LOG_FILE, 'a') as logfile:
|
||||
# we link stdout to a file in order to catch
|
||||
# eventual errors happening before the Server has
|
||||
# opened its logger.
|
||||
try:
|
||||
if os.name == 'nt':
|
||||
# Windows requires special care
|
||||
|
|
@ -159,24 +162,20 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
process = Popen(server_twistd_cmd, env=getenv(), bufsize=-1,
|
||||
stdout=logfile, stderr=STDOUT,
|
||||
creationflags=create_no_window)
|
||||
|
||||
else:
|
||||
process = Popen(server_twistd_cmd, env=getenv(), bufsize=-1,
|
||||
stdout=logfile, stderr=STDOUT)
|
||||
except Exception:
|
||||
self.factory.portal.server_process_id = None
|
||||
logger.log_trace()
|
||||
logfile.flush()
|
||||
return 0
|
||||
# there is a short window before the server logger is up where we must
|
||||
# catch the stdout of the Server or eventual tracebacks will be lost.
|
||||
# with process.stdout as out:
|
||||
# logger.log_server(out.readlines())
|
||||
|
||||
# store the pid and launch argument for future reference
|
||||
self.factory.portal.server_process_id = process.pid
|
||||
self.factory.portal.server_twistd_cmd = server_twistd_cmd
|
||||
logfile.flush()
|
||||
if process:
|
||||
# avoid zombie-process
|
||||
process.wait()
|
||||
return process.pid
|
||||
return 0
|
||||
|
||||
def wait_for_disconnect(self, callback, *args, **kwargs):
|
||||
"""
|
||||
|
|
@ -414,7 +413,8 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
|
||||
elif operation == amp.PSYNC: # portal sync
|
||||
# Server has (re-)connected and wants the session data from portal
|
||||
self.factory.server_info_dict = kwargs.get("info_dict", {})
|
||||
self.factory.portal.server_info_dict = kwargs.get("info_dict", {})
|
||||
self.factory.portal.server_process_id = kwargs.get("spid", None)
|
||||
# this defaults to 'shutdown' or whatever value set in server_stop
|
||||
server_restart_mode = self.factory.portal.server_restart_mode
|
||||
|
||||
|
|
|
|||
|
|
@ -39,11 +39,6 @@ except Exception:
|
|||
PORTAL_SERVICES_PLUGIN_MODULES = [mod_import(module) for module in make_iter(settings.PORTAL_SERVICES_PLUGIN_MODULES)]
|
||||
LOCKDOWN_MODE = settings.LOCKDOWN_MODE
|
||||
|
||||
PORTAL_PIDFILE = ""
|
||||
if os.name == 'nt':
|
||||
# For Windows we need to handle pid files manually.
|
||||
PORTAL_PIDFILE = os.path.join(settings.GAME_DIR, "server", 'portal.pid')
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Evennia Portal settings
|
||||
# -------------------------------------------------------------
|
||||
|
|
@ -113,8 +108,10 @@ class Portal(object):
|
|||
self.sessions = PORTAL_SESSIONS
|
||||
self.sessions.portal = self
|
||||
self.process_id = os.getpid()
|
||||
|
||||
self.server_process_id = None
|
||||
self.server_restart_mode = "shutdown"
|
||||
self.server_info_dict = {}
|
||||
|
||||
# set a callback if the server is killed abruptly,
|
||||
# by Ctrl-C, reboot etc.
|
||||
|
|
@ -163,9 +160,7 @@ class Portal(object):
|
|||
return
|
||||
self.sessions.disconnect_all()
|
||||
self.set_restart_mode(restart)
|
||||
if os.name == 'nt' and os.path.exists(PORTAL_PIDFILE):
|
||||
# for Windows we need to remove pid files manually
|
||||
os.remove(PORTAL_PIDFILE)
|
||||
|
||||
if not _reactor_stopping:
|
||||
# shutting down the reactor will trigger another signal. We set
|
||||
# a flag to avoid loops.
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@ SERVER_STARTSTOP_MODULE = mod_import(settings.AT_SERVER_STARTSTOP_MODULE)
|
|||
SERVER_SERVICES_PLUGIN_MODULES = [mod_import(module) for module in make_iter(settings.SERVER_SERVICES_PLUGIN_MODULES)]
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# ------------------------------------------------------------
|
||||
# Evennia Server settings
|
||||
#------------------------------------------------------------
|
||||
# ------------------------------------------------------------
|
||||
|
||||
SERVERNAME = settings.SERVERNAME
|
||||
VERSION = get_evennia_version()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue