Start using asyncio for signals
This commit is contained in:
parent
f26d95963e
commit
c6b5aab917
3 changed files with 18 additions and 26 deletions
|
|
@ -7,7 +7,7 @@ An extremely modulable IRC bot, built around XML configuration files!
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
*nemubot* requires at least Python 3.3 to work.
|
*nemubot* requires at least Python 3.4 to work, as it uses `asyncio`.
|
||||||
|
|
||||||
Connecting to SSL server requires [this patch](http://bugs.python.org/issue27629).
|
Connecting to SSL server requires [this patch](http://bugs.python.org/issue27629).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,25 +178,13 @@ def main():
|
||||||
daemonize(args.socketfile, not args.no_attach)
|
daemonize(args.socketfile, not args.no_attach)
|
||||||
|
|
||||||
# Signals handling
|
# Signals handling
|
||||||
def sigtermhandler(signum, frame):
|
def sigtermhandler():
|
||||||
"""On SIGTERM and SIGINT, quit nicely"""
|
"""On SIGTERM and SIGINT, quit nicely"""
|
||||||
context.quit()
|
context.quit()
|
||||||
signal.signal(signal.SIGINT, sigtermhandler)
|
context.loop.add_signal_handler(signal.SIGINT, sigtermhandler)
|
||||||
signal.signal(signal.SIGTERM, sigtermhandler)
|
context.loop.add_signal_handler(signal.SIGTERM, sigtermhandler)
|
||||||
|
|
||||||
def sighuphandler(signum, frame):
|
def sigusr1handler():
|
||||||
"""On SIGHUP, perform a deep reload"""
|
|
||||||
nonlocal context
|
|
||||||
|
|
||||||
logger.debug("SIGHUP receive, iniate reload procedure...")
|
|
||||||
|
|
||||||
# Reload configuration file
|
|
||||||
for path in args.files:
|
|
||||||
if os.path.isfile(path):
|
|
||||||
sync_act("loadconf", path)
|
|
||||||
signal.signal(signal.SIGHUP, sighuphandler)
|
|
||||||
|
|
||||||
def sigusr1handler(signum, frame):
|
|
||||||
"""On SIGHUSR1, display stacktraces"""
|
"""On SIGHUSR1, display stacktraces"""
|
||||||
import threading, traceback
|
import threading, traceback
|
||||||
for threadId, stack in sys._current_frames().items():
|
for threadId, stack in sys._current_frames().items():
|
||||||
|
|
@ -208,24 +196,21 @@ def main():
|
||||||
logger.debug("########### Thread %s:\n%s",
|
logger.debug("########### Thread %s:\n%s",
|
||||||
thName,
|
thName,
|
||||||
"".join(traceback.format_stack(stack)))
|
"".join(traceback.format_stack(stack)))
|
||||||
signal.signal(signal.SIGUSR1, sigusr1handler)
|
context.loop.add_signal_handler(signal.SIGUSR1, sigusr1handler)
|
||||||
|
|
||||||
# Store PID to pidfile
|
# Store PID to pidfile
|
||||||
if args.pidfile is not None:
|
if args.pidfile is not None:
|
||||||
with open(args.pidfile, "w+") as f:
|
with open(args.pidfile, "w+") as f:
|
||||||
f.write(str(os.getpid()))
|
f.write(str(os.getpid()))
|
||||||
|
|
||||||
# context can change when performing an hotswap, always join the latest context
|
context.start()
|
||||||
oldcontext = None
|
context.loop.run_forever()
|
||||||
while oldcontext != context:
|
context.join()
|
||||||
oldcontext = context
|
|
||||||
context.start()
|
|
||||||
context.join()
|
|
||||||
|
|
||||||
# Wait for consumers
|
# Wait for consumers
|
||||||
logger.info("Waiting for other threads shuts down...")
|
logger.info("Waiting for other threads shuts down...")
|
||||||
if args.debug:
|
if args.debug:
|
||||||
sigusr1handler(0, None)
|
sigusr1handler()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
import logging
|
import logging
|
||||||
from multiprocessing import JoinableQueue
|
from multiprocessing import JoinableQueue
|
||||||
|
|
@ -40,7 +41,7 @@ class Bot(threading.Thread):
|
||||||
"""Class containing the bot context and ensuring key goals"""
|
"""Class containing the bot context and ensuring key goals"""
|
||||||
|
|
||||||
def __init__(self, ip="127.0.0.1", modules_paths=list(),
|
def __init__(self, ip="127.0.0.1", modules_paths=list(),
|
||||||
data_store=datastore.Abstract(), debug=False):
|
data_store=datastore.Abstract(), debug=False, loop=None):
|
||||||
"""Initialize the bot context
|
"""Initialize the bot context
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
|
|
@ -59,6 +60,9 @@ class Bot(threading.Thread):
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.stop = None
|
self.stop = None
|
||||||
|
|
||||||
|
#
|
||||||
|
self.loop = loop if loop is not None else asyncio.get_event_loop()
|
||||||
|
|
||||||
# External IP for accessing this bot
|
# External IP for accessing this bot
|
||||||
import ipaddress
|
import ipaddress
|
||||||
self.ip = ipaddress.ip_address(ip)
|
self.ip = ipaddress.ip_address(ip)
|
||||||
|
|
@ -522,6 +526,9 @@ class Bot(threading.Thread):
|
||||||
for cnsr in k:
|
for cnsr in k:
|
||||||
cnsr.stop = True
|
cnsr.stop = True
|
||||||
|
|
||||||
|
logger.info("Closing event loop")
|
||||||
|
self.loop.stop()
|
||||||
|
|
||||||
if self.stop is False or sync_queue is not None:
|
if self.stop is False or sync_queue is not None:
|
||||||
self.stop = True
|
self.stop = True
|
||||||
sync_act("end")
|
sync_act("end")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue