Skip to content

Commit

Permalink
flake8
Browse files Browse the repository at this point in the history
  • Loading branch information
hannosch committed Jul 24, 2016
1 parent 8e52f97 commit 966f7df
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 108 deletions.
23 changes: 13 additions & 10 deletions src/Lifetime/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import sys, asyncore, time
import asyncore
import time

_shutdown_phase = 0
_shutdown_timeout = 30 # seconds per phase
_shutdown_timeout = 30 # seconds per phase

# The shutdown phase counts up from 0 to 4.
#
Expand All @@ -23,7 +24,8 @@
# of time that it has currently been in that phase. This method should return
# true if it does not yet want shutdown to proceed to the next phase.

def shutdown(exit_code,fast = 0):

def shutdown(exit_code, fast=0):
global _shutdown_phase
global _shutdown_timeout
if _shutdown_phase == 0:
Expand All @@ -38,46 +40,47 @@ def shutdown(exit_code,fast = 0):
# enough, but still clean.
_shutdown_timeout = 1.0


def loop():
# Run the main loop until someone calls shutdown()
lifetime_loop()
# Gradually close sockets in the right order, while running a select
# loop to allow remaining requests to trickle away.
graceful_shutdown_loop()


def lifetime_loop():
# The main loop. Stay in here until we need to shutdown
map = asyncore.socket_map
timeout = 30.0
while map and _shutdown_phase == 0:
asyncore.poll(timeout, map)


def graceful_shutdown_loop():
# The shutdown loop. Allow various services to shutdown gradually.
global _shutdown_phase
timestamp = time.time()
timeout = 1.0
map = asyncore.socket_map
while map and _shutdown_phase < 4:
time_in_this_phase = time.time()-timestamp
time_in_this_phase = time.time() - timestamp
veto = 0
for fd,obj in map.items():
for fd, obj in map.items():
try:
fn = getattr(obj,'clean_shutdown_control')
fn = getattr(obj, 'clean_shutdown_control')
except AttributeError:
pass
else:
try:
veto = veto or fn(_shutdown_phase,time_in_this_phase)
veto = veto or fn(_shutdown_phase, time_in_this_phase)
except:
obj.handle_error()
if veto and time_in_this_phase<_shutdown_timeout:
if veto and time_in_this_phase < _shutdown_timeout:
# Any open socket handler can veto moving on to the next shutdown
# phase. (but not forever)
asyncore.poll(timeout, map)
else:
# No vetos? That is one step closer to shutting down
_shutdown_phase += 1
timestamp = time.time()

12 changes: 8 additions & 4 deletions src/Signals/SignalHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
##############################################################################
"""Signal handling dispatcher."""

import sys, os
import os
import sys
import signal
from logging import getLogger

LOG = getLogger('SignalHandler')
LOG = getLogger('SignalHandler')

class SignalHandler:

class SignalHandler(object):

def __init__(self):
self.registry = {}
Expand Down Expand Up @@ -52,7 +54,8 @@ def signalHandler(self, signum, frame):
for handler in self.registry.get(signum, []):
# Never let a bad handler prevent the standard signal
# handlers from running.
try: handler()
try:
handler()
except SystemExit:
# if we trap SystemExit, we can't restart
raise
Expand All @@ -62,6 +65,7 @@ def signalHandler(self, signum, frame):

_signals = None


def get_signal_name(n):
"""Return the symbolic name for signal n.
Expand Down
23 changes: 14 additions & 9 deletions src/Signals/Signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

from .threads import dump_threads


logger = logging.getLogger("Z2")

if os.name == 'nt':
Expand All @@ -37,11 +36,12 @@
else:
from SignalHandler import SignalHandler


def shutdownFastHandler():
"""Shutdown cleanly on SIGTERM. This is registered first,
so it should be called after all other handlers."""
logger.info("Shutting down fast")
Lifetime.shutdown(0,fast=1)
Lifetime.shutdown(0, fast=1)


def shutdownHandler():
Expand All @@ -50,6 +50,7 @@ def shutdownHandler():
logger.info("Shutting down")
sys.exit(0)


def restartHandler():
"""Restart cleanly on SIGHUP. This is registered first, so it
should be called after all other SIGHUP handlers."""
Expand All @@ -59,11 +60,11 @@ def restartHandler():

def showStacks():
"""Dump a stracktrace of all threads on the console."""
print dump_threads()
print(dump_threads())
sys.stdout.flush()


class LogfileReopenHandler:
class LogfileReopenHandler(object):
"""Reopen log files on SIGUSR2.
This is registered first, so it should be called after all other
Expand All @@ -77,12 +78,15 @@ def __call__(self):
log.reopen()
logger.info("Log files reopened successfully")


# On Windows, a 'reopen' is useless - the file can not be renamed
# while open, so we perform a trivial 'rotate'.
class LogfileRotateHandler:
"""Rotate log files on SIGUSR2. Only called on Windows. This is
registered first, so it should be called after all other SIGUSR2
handlers."""
class LogfileRotateHandler(object):
"""
Rotate log files on SIGUSR2. Only called on Windows. This is
registered first, so it should be called after all other SIGUSR2
handlers.
"""
def __init__(self, loggers):
self.loggers = [log for log in loggers if log is not None]

Expand All @@ -95,6 +99,7 @@ def __call__(self):
handler.rotate()
logger.info("Log files rotation complete")


def registerZopeSignals(loggers):
from signal import SIGTERM, SIGINT
try:
Expand All @@ -111,7 +116,7 @@ def registerZopeSignals(loggers):

mod_wsgi = True
try:
from mod_wsgi import version
from mod_wsgi import version # NOQA
except ImportError:
mod_wsgi = False

Expand Down
72 changes: 38 additions & 34 deletions src/Signals/WinSignalHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#
# One event is used per signal, and the event name is based on both the
# Zope process ID and the signal number. For example, assuming a process
# ID of 123, a SIGINT handler would create an event called "Zope-123-2"
# ID of 123, a SIGINT handler would create an event called "Zope-123-2"
# (as signal.SIGINT==2). The logfile reopen handler uses an event named
# "Zope-123-12" (as the logfile handler uses SIGUSR2, which == 12)

Expand All @@ -35,13 +35,14 @@

# NOTE: There is one huge semantic difference between these "signals"
# and signals on Unix. On Windows, the signals are delivered asynchronously
# to a thread inside this module. This thread calls the event handler
# to a thread inside this module. This thread calls the event handler
# directly - there is no magic to switch the call back to the main thread.
# If this is a problem (not currently, but likely later), one option may be
# to add yet another asyncore handler - the thread in this module could
# If this is a problem (not currently, but likely later), one option may be
# to add yet another asyncore handler - the thread in this module could
# then "post" the request to the main thread via this asyncore handler.

import sys, os
import os
import sys
import signal
import threading
import asyncore
Expand All @@ -62,7 +63,7 @@
import ntsecuritycon

import logging
logger=logging.getLogger("WinSignalHandler")
logger = logging.getLogger("WinSignalHandler")

# We simulate signals via win32 named events. This is the event name
# prefix we use - the "signal number" is appended to this name.
Expand All @@ -76,15 +77,16 @@
if winver[0] >= 5 and winver[3] == 2:
event_name_prefix = "Global\\" + event_name_prefix


def createEventSecurityObject():
# Create a security object giving World read/write access,
# but only "Owner" modify access.
sa = pywintypes.SECURITY_ATTRIBUTES()
sidEveryone = pywintypes.SID()
sidEveryone.Initialize(ntsecuritycon.SECURITY_WORLD_SID_AUTHORITY,1)
sidEveryone.Initialize(ntsecuritycon.SECURITY_WORLD_SID_AUTHORITY, 1)
sidEveryone.SetSubAuthority(0, ntsecuritycon.SECURITY_WORLD_RID)
sidCreator = pywintypes.SID()
sidCreator.Initialize(ntsecuritycon.SECURITY_CREATOR_SID_AUTHORITY,1)
sidCreator.Initialize(ntsecuritycon.SECURITY_CREATOR_SID_AUTHORITY, 1)
sidCreator.SetSubAuthority(0, ntsecuritycon.SECURITY_CREATOR_OWNER_RID)

acl = pywintypes.ACL()
Expand All @@ -94,17 +96,19 @@ def createEventSecurityObject():
sa.SetSecurityDescriptorDacl(1, acl, 0)
return sa


def wakeSelect():
"""Interrupt a sleeping asyncore 'select' call"""
# What is the right thing to do here?
# What is the right thing to do here?
# asyncore.close_all() works, but I fear that would
# prevent the poll based graceful cleanup code from working.
# This seems to work :)
for fd, obj in asyncore.socket_map.items():
if hasattr(obj, "pull_trigger"):
obj.pull_trigger()

class SignalHandler:

class SignalHandler(object):

def __init__(self):
self.registry = {}
Expand All @@ -113,7 +117,7 @@ def __init__(self):
self.shutdown_requested = False
# Register a "console control handler" for Ctrl+C/Break notification.
SetConsoleCtrlHandler(consoleCtrlHandler)

# Start the thread that is watching for events.
thread = threading.Thread(target=self.signalCheckerThread)
# If something goes terribly wrong, don't wait for this thread!
Expand All @@ -126,20 +130,15 @@ def shutdown(self):
logger.debug("signal handler shutdown starting.")
self.shutdown_requested = 1
win32event.SetEvent(self.admin_event_handle)
# sadly, this can deadlock at shutdown when Ctrl+C is used
# (although not then the event is used to trigger shutdown)
# at least in build 204. Further updates as they come to hand...
# Remove the Windows control handler
#SetConsoleCtrlHandler(consoleCtrlHandler, 0)
self.signal_thread.join(5) # should never block for long!
self.signal_thread.join(5) # should never block for long!

self.registry = None
self.event_handles = None
self.admin_event_handle = None
logger.debug("signal handler shutdown complete.")

def consoleCtrlHandler(self, ctrlType):
"""Called by Windows on a new thread whenever a console control
"""Called by Windows on a new thread whenever a console control
event is raised."""
logger.debug("Windows control event %d" % ctrlType)
sig = None
Expand All @@ -153,13 +152,13 @@ def consoleCtrlHandler(self, ctrlType):
# CTRL_CLOSE_EVENT gives us 5 seconds before displaying
# the "End process" dialog - so treat as 'fast'
sig = signal.SIGTERM
elif ctrlType in (win32con.CTRL_LOGOFF_EVENT,
elif ctrlType in (win32con.CTRL_LOGOFF_EVENT,
win32con.CTRL_SHUTDOWN_EVENT):
# MSDN says:
# "Note that this signal is received only by services.
# Interactive applications are terminated at logoff, so
# "Note that this signal is received only by services.
# Interactive applications are terminated at logoff, so
# they are not present when the system sends this signal."
# We can therefore ignore it (our service framework
# We can therefore ignore it (our service framework
# manages shutdown in this case)
pass
else:
Expand All @@ -169,9 +168,9 @@ def consoleCtrlHandler(self, ctrlType):
# that we don't wake the select loop until after the shutdown
# flags have been set.
result = 0
if sig is not None and self.registry.has_key(sig):
if sig is not None and sig in self.registry:
self.signalHandler(sig, None)
result = 1 # don't call other handlers.
result = 1 # don't call other handlers.
return result

def signalCheckerThread(self):
Expand Down Expand Up @@ -210,7 +209,8 @@ def registerHandler(self, signum, handler):
# Let the worker thread know there is a new handle.
win32event.SetEvent(self.admin_event_handle)
signame = get_signal_name(signum)
logger.debug("Installed sighandler for %s (%s)" % (signame, event_name))
logger.debug(
"Installed sighandler for %s (%s)" % (signame, event_name))
items.insert(0, handler)

def getRegisteredSignals(self):
Expand All @@ -226,20 +226,23 @@ def signalHandler(self, signum, frame):
for handler in self.registry.get(signum, []):
# Never let a bad handler prevent the standard signal
# handlers from running.
try: handler()
except SystemExit, rc:
# On Unix, signals are delivered to the main thread, so a
try:
handler()
except SystemExit as rc:
# On Unix, signals are delivered to the main thread, so a
# SystemExit does the right thing. On Windows, we are on
# our own thread, so throwing SystemExit there isn't a great
# idea. Just shutdown the main loop.
logger.debug("Trapped SystemExit(%s) - doing Lifetime shutdown" % (rc,))
logger.debug(
"Trapped SystemExit(%s) - doing Lifetime shutdown" % rc)
Lifetime.shutdown(rc)
except:
logger.exception("A handler for %s failed!'" % signame)
wakeSelect() # trigger a walk around the Lifetime loop.
wakeSelect() # trigger a walk around the Lifetime loop.

_signals = None


def get_signal_name(n):
"""Return the symbolic name for signal n.
Expand All @@ -257,19 +260,20 @@ def get_signal_name(n):
_signals[v] = k
# extra ones that aren't (weren't?) in Windows.
for name, val in ("SIGHUP", 1), ("SIGUSR1", 10), ("SIGUSR2", 12):
if not _signals.has_key(name):
if name not in _signals:
_signals[val] = name

return _signals.get(n, 'signal %d' % n)

# The win32 ConsoleCtrlHandler

def consoleCtrlHandler(ctrlType):
# The win32 ConsoleCtrlHandler
return SignalHandler.consoleCtrlHandler(ctrlType)

# The SignalHandler is actually a singleton.
SignalHandler = SignalHandler()

# Need to be careful at shutdown - the 'signal watcher' thread which triggers
# the shutdown may still be running when the main thread terminates and
# Need to be careful at shutdown - the 'signal watcher' thread which triggers
# the shutdown may still be running when the main thread terminates and
# Python starts cleaning up.
atexit.register(SignalHandler.shutdown)
Loading

0 comments on commit 966f7df

Please sign in to comment.