From a2cbe2032565c61b971659aed28ebd4b096ea87d Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Wed, 23 Feb 2022 13:06:12 +0000 Subject: [PATCH] fix rediss ssl eventlet sslerror bug eventlet works by monkey-patching core IO libraries (such as ssl) to be non-blocking. However, there's currently a bug: In the normal socket library it may throw a timeout error as a `socket.timeout` exception. However eventlet.green.ssl's patch raises an ssl.SSLError('timed out',) instead. redispy handles socket.timeout but not ssl.SSLError, so we solve this by monkey patching the monkey patching code to raise the correct exception type :scream: Note: This code should _only_ be called when we're using eventlets, or we'll run into issues with regular code failing with max recursion errors. With that in mind we put this code in gunicorn_config, as that isn't imported when we run celery or run flask locally. --- gunicorn_config.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gunicorn_config.py b/gunicorn_config.py index 62223af54..c4844df4b 100644 --- a/gunicorn_config.py +++ b/gunicorn_config.py @@ -2,6 +2,8 @@ import os import sys import traceback import gunicorn +import eventlet +import socket from gds_metrics.gunicorn import child_exit # noqa @@ -30,3 +32,22 @@ def on_exit(server): def worker_int(worker): worker.log.info("worker: received SIGINT {}".format(worker.pid)) + + +def fix_ssl_monkeypatching(): + """ + eventlet works by monkey-patching core IO libraries (such as ssl) to be non-blocking. However, there's currently + a bug: In the normal socket library it may throw a timeout error as a `socket.timeout` exception. However + eventlet.green.ssl's patch raises an ssl.SSLError('timed out',) instead. redispy handles socket.timeout but not + ssl.SSLError, so we solve this by monkey patching the monkey patching code to raise the correct exception type + :scream: + + https://github.com/eventlet/eventlet/issues/692 + """ + # this has probably already been called somewhere in gunicorn internals, however, to be sure, we invoke it again. + # eventlet.monkey_patch can be called multiple times without issue + eventlet.monkey_patch() + eventlet.green.ssl.timeout_exc = socket.timeout + + +fix_ssl_monkeypatching()