我该如何处理来自不同Gunicorn叉交错的异常?(How do I handle interlea

2019-10-18 05:23发布

我有一个分叉Gunicorn环境中运行的应用程序瓶,但踪迹在日志文件中得到交错。 每个叉都可以有自己的日志文件? 或者可以每个记录有独家访问,同时写入日志?

Answer 1:

每个叉都可以有自己的日志文件?

是的,虽然你可能不需要,或者想,那个。 要做到这一点最简单的方法是只要坚持os.getpid()某处的文件名。

或者可以每个记录有独家访问,同时写入日志?

有几个方法可以做到这一点,但明显的是只需更换默认threading.RLockloggingmultiprocessing.RLock

根据该文档 ,你通过重写做到这一点createLockacquirerelease 。 所以:

class CrossProcessFileHandler(logging.FileHandler):
    def createLock(self):
        self.lock = multiprocessing.RLock()
    def acquire(self):
        self.lock.acquire()
    def release(self):
        self.lock.release()

现在只用这个来代替FileHandler

只需确保在初始化父进程的记录; 如果每个孩子建立自己独立的跨进程的锁,那也不会帮助任何东西。


请注意,如果你关心跨平台移植,为预期的POSIX但Windows明显琐碎的代码可能会奏效。 (我不知道有足够的了解如何gunicorn在Windows上运行猜...)但是你可以只是没有锁定在Windows处理,因为在默认情况下, FileHandler打开进行独占访问文件,写和关闭,这意味着文件系统已经在做你锁定你。 (这招不会对POSIX因为因为没有这种东西的工作Windows风格的独家访问,或者说,有在大多数平台和文件系统等价,但它们不是便携式的,你必须走出去的你办法做到这一点,而不是默认情况下,无论你想不想要得到它的。)


实施acquirerelease为CPython的2.3至3.3所有内置处理器和每隔实施一直只是被这样的:

if self.lock:
    self.lock.acquire()

所以,你会看到,仅覆盖作弊代码createLock 。 我已经是多次做我自己,我已经在各种不同的第三方项目看到它。 不过说真的,文档并不能保证,所以你应该重写其他两个为好。



Answer 2:

@abarnert解决方案工作得非常好,但它需要的子类项目中使用的每一个处理器。 它可以由类装饰被简化:

def multiprocess_handler(cls):
    class MultiProcessHandler(cls):
        def createLock(self):
            self.lock = multiprocessing.RLock()
    return MultiProcessHandler

MFileHandler = multiprocess_handler(logging.FileHandler)
MRotatingFileHandler = multiprocess_handler(logging.handlers.RotatingFileHandler)
# etc.


文章来源: How do I handle interleaved exceptions from different Gunicorn forks?