diff options
author | Ken Payson <kpayson@google.com> | 2016-06-10 13:19:31 -0700 |
---|---|---|
committer | Ken Payson <kpayson@google.com> | 2016-06-13 15:38:53 -0700 |
commit | ed7428526cea1f7b54a126ef9cdb2c1456c47f2c (patch) | |
tree | 64d4239e374dbbc2da4be8153db816c29b5a4350 /src/python/grpcio/grpc/_common.py | |
parent | 68e5ecbee4882a74b16a6e22d935d68798016804 (diff) |
Added cleanup to the server thread's join method.
When the Python Interpreter exits, it first attempts to join any
outstanding threads. This is problematic if a server is created
as a top-level variable or referenced by a reference cycle, as join()
will hang. This adds cleanup behavior to the server thread's join().
Diffstat (limited to 'src/python/grpcio/grpc/_common.py')
-rw-r--r-- | src/python/grpcio/grpc/_common.py | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/python/grpcio/grpc/_common.py b/src/python/grpcio/grpc/_common.py index b8688a0149..1fd1704f18 100644 --- a/src/python/grpcio/grpc/_common.py +++ b/src/python/grpcio/grpc/_common.py @@ -30,6 +30,8 @@ """Shared implementation.""" import logging +import threading +import time import six @@ -110,3 +112,43 @@ def fully_qualified_method(group, method): group = _encode(group) method = _encode(method) return b'/' + group + b'/' + method + + +class CleanupThread(threading.Thread): + """A threading.Thread subclass supporting custom behavior on join(). + + On Python Interpreter exit, Python will attempt to join outstanding threads + prior to garbage collection. We may need to do additional cleanup, and + we accomplish this by overriding the join() method. + """ + + def __init__(self, behavior, group=None, target=None, name=None, + args=(), kwargs={}): + """Constructor. + + Args: + behavior (function): Function called on join() with a single + argument, timeout, indicating the maximum duration of + `behavior`, or None indicating `behavior` has no deadline. + `behavior` must be idempotent. + group (None): should be None. Reseved for future extensions + when ThreadGroup is implemented. + target (function): The function to invoke when this thread is + run. Defaults to None. + name (str): The name of this thread. Defaults to None. + args (tuple[object]): A tuple of arguments to pass to `target`. + kwargs (dict[str,object]): A dictionary of keyword arguments to + pass to `target`. + """ + super(CleanupThread, self).__init__(group=group, target=target, + name=name, args=args, kwargs=kwargs) + self._behavior = behavior + + def join(self, timeout=None): + start_time = time.time() + self._behavior(timeout) + end_time = time.time() + if timeout is not None: + timeout -= end_time - start_time + timeout = max(timeout, 0) + super(CleanupThread, self).join(timeout) |