PyBitmessage-2021-04-27/src/shutdown.py
Dmitri Bogomolov 7a89109fc9
New logging approach in order to reduce imports from submodules
and use logging without risk of circular import. Only subpackage
that imports from debug is bitmessageqt - because it also uses
debug.resetLogging().
Instead of from debug import logger is now recommended to use:

import logging

logger = logging.getLogger('default')

All subclasses of StoppableThread now have a logger attribute.
All threading related stuff except for set_thread_name()
was moved from helper_threading to network.threads.

Fixed two my mistakes from previous edit of debug in a1a8d3a:

 - logger.handlers is not dict but iterable
 - sys.excepthook should be set unconditionally
2019-10-18 09:35:24 +03:00

87 lines
2.9 KiB
Python

import os
import Queue
import threading
import time
import shared
import state
from debug import logger
from helper_sql import sqlQuery, sqlStoredProcedure
from inventory import Inventory
from knownnodes import saveKnownNodes
from network.threads import StoppableThread
from queues import (
addressGeneratorQueue, objectProcessorQueue, UISignalQueue, workerQueue)
def doCleanShutdown():
# Used to tell proof of work worker threads
# and the objectProcessorThread to exit.
state.shutdown = 1
objectProcessorQueue.put(('checkShutdownVariable', 'no data'))
for thread in threading.enumerate():
if thread.isAlive() and isinstance(thread, StoppableThread):
thread.stopThread()
UISignalQueue.put((
'updateStatusBar',
'Saving the knownNodes list of peers to disk...'))
logger.info('Saving knownNodes list of peers to disk')
saveKnownNodes()
logger.info('Done saving knownNodes list of peers to disk')
UISignalQueue.put((
'updateStatusBar',
'Done saving the knownNodes list of peers to disk.'))
logger.info('Flushing inventory in memory out to disk...')
UISignalQueue.put((
'updateStatusBar',
'Flushing inventory in memory out to disk.'
' This should normally only take a second...'))
Inventory().flush()
# Verify that the objectProcessor has finished exiting. It should have
# incremented the shutdown variable from 1 to 2. This must finish before
# we command the sqlThread to exit.
while state.shutdown == 1:
time.sleep(.1)
# Wait long enough to guarantee that any running proof of work worker
# threads will check the shutdown variable and exit. If the main thread
# closes before they do then they won't stop.
time.sleep(.25)
for thread in threading.enumerate():
if (thread is not threading.currentThread() and
isinstance(thread, StoppableThread) and
thread.name != 'SQL'):
logger.debug("Waiting for thread %s", thread.name)
thread.join()
# This one last useless query will guarantee that the previous flush
# committed and that the
# objectProcessorThread committed before we close the program.
sqlQuery('SELECT address FROM subscriptions')
logger.info('Finished flushing inventory.')
sqlStoredProcedure('exit')
# flush queues
for queue in (
workerQueue, UISignalQueue, addressGeneratorQueue,
objectProcessorQueue):
while True:
try:
queue.get(False)
queue.task_done()
except Queue.Empty:
break
if shared.thisapp.daemon or not state.enableGUI: # FIXME redundant?
logger.info('Clean shutdown complete.')
shared.thisapp.cleanup()
os._exit(0)
else:
logger.info('Core shutdown complete.')
for thread in threading.enumerate():
logger.debug('Thread %s still running', thread.name)