Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AAP-27692] Add middleware that apps can use to handle graceful timeout signal #581

Merged
merged 1 commit into from
Aug 27, 2024

Conversation

kdelee
Copy link
Member

@kdelee kdelee commented Aug 21, 2024

uwsgi 2.0.22+ offers option to send a user-defined signal at for a "graceful" timeout before the real harakiri occurs (we can configure any signal we want -- so we can go with SIGABRT)

gunicorn sends SIGABRT (signal 6) as graceful timeout signal before sending SIGKILL.

Apps can use this middleware to log a traceback indicating what code was executing when the graceful timeout signal was received.

Will use this instead of middleware defined in awx for ansible/awx#15447

@kdelee
Copy link
Member Author

kdelee commented Aug 21, 2024

dropped introspecting into the X-REQUEST-ID header because I think if apps are following

## Logging request IDs
django-ansible-base provides machinery (middleware and logging filters) to inject the request id into the logging format string.
The request id should come through as a header in the request, `X-Request-Id` (case-insensitive).
To enable logging of request ids, make the following changes to your application's `settings.py`:
1. Add `'ansible_base.lib.middleware.logging.LogRequestMiddleware'` to `MIDDLEWARE`. This is a middleware that simply
adds the current request object to the thread-local state, so that the logging filter (in the following steps) can
make use of it.
2. Configure `LOGGING`
a. Add the logging filter to `LOGGING['filters']`
b. Enable the filter in `LOGGING['handlers']`
c. Make use of the `request_id` parameter in `LOGGING['formatters']`
will "just work"

@kdelee kdelee force-pushed the timeout_traceback_middleware branch 3 times, most recently from 56a9e2d to fec8a71 Compare August 21, 2024 18:54
test_app/apps.py Outdated Show resolved Hide resolved
@AlanCoding
Copy link
Member

kdelee#1

@kdelee kdelee force-pushed the timeout_traceback_middleware branch 3 times, most recently from 7f43463 to 6023e24 Compare August 21, 2024 20:21
@kdelee kdelee requested a review from AlanCoding August 21, 2024 21:06
@kdelee kdelee force-pushed the timeout_traceback_middleware branch 7 times, most recently from 731809d to 6fb318c Compare August 22, 2024 17:59
Copy link
Member

@AlanCoding AlanCoding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. Quality utility.

@kdelee kdelee force-pushed the timeout_traceback_middleware branch from ae1c43e to 85d4464 Compare August 26, 2024 18:53
@kdelee kdelee changed the title Add middleware that apps can use to handle graceful timeout signal [AAP-27692] Add middleware that apps can use to handle graceful timeout signal Aug 27, 2024
@kdelee kdelee force-pushed the timeout_traceback_middleware branch 3 times, most recently from d653471 to 9ceba08 Compare August 27, 2024 14:11
@kdelee
Copy link
Member Author

kdelee commented Aug 27, 2024

re-confirmed with awx PR ansible/awx#15447

tools_awx_1       | Tue Aug 27 14:09:09 2024 - *** HARAKIRI ON WORKER 1 (pid: 2908, try: 1, graceful: yes) ***
tools_awx_1       | Tue Aug 27 14:09:09 2024 - HARAKIRI !!! worker 1 status !!!
tools_awx_1       | Tue Aug 27 14:09:09 2024 - HARAKIRI [core 0] 172.23.0.1 - GET /api/ since 1724767747
tools_awx_1       | Tue Aug 27 14:09:09 2024 - HARAKIRI !!! end of worker 1 status !!!
tools_awx_1       | Tue Aug 27 14:09:09 2024 - HARAKIRI: graceful termination attempt on worker 1 with signal 6. Next harakiri: 1724767750
tools_awx_1       | Tue Aug 27 14:09:09 2024 - HARAKIRI triggered by worker 1 core 0 !!!
tools_awx_1       | 2024-08-27 14:09:09,673 ERROR    [d459e624] ansible_base.lib.middleware.logging.log_request Received graceful timeout signal for GET
tools_awx_1       |                 path: /api/ while in stack:   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/wsgi.py", line 124, in __call__
tools_awx_1       |     response = self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/base.py", line 140, in get_response
tools_awx_1       |     response = self._middleware_chain(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/debug_toolbar/middleware.py", line 48, in __call__
tools_awx_1       |     return self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django_guid/middleware.py", line 79, in middleware
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/ansible_base/lib/middleware/logging/log_request.py", line 40, in __call__
tools_awx_1       |     return self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/corsheaders/middleware.py", line 56, in __call__
tools_awx_1       |     result = self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/social_django/middleware.py", line 28, in __call__
tools_awx_1       |     return self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/crum/__init__.py", line 97, in __call__
tools_awx_1       |     response = self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/deprecation.py", line 134, in __call__
tools_awx_1       |     response = response or self.get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
tools_awx_1       |     response = get_response(request)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
tools_awx_1       |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
tools_awx_1       |   File "/usr/lib64/python3.11/contextlib.py", line 81, in inner
tools_awx_1       |     return func(*args, **kwds)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
tools_awx_1       |     return view_func(*args, **kwargs)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/views/generic/base.py", line 104, in view
tools_awx_1       |     return self.dispatch(request, *args, **kwargs)
tools_awx_1       |   File "/awx_devel/awx/api/generics.py", line 351, in dispatch
tools_awx_1       |     return super(APIView, self).dispatch(request, *args, **kwargs)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/rest_framework/views.py", line 506, in dispatch
tools_awx_1       |     response = handler(request, *args, **kwargs)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/decorators.py", line 46, in _wrapper
tools_awx_1       |     return bound_method(*args, **kwargs)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
tools_awx_1       |     response = view_func(request, *args, **kwargs)
tools_awx_1       |   File "/awx_devel/awx/api/views/root.py", line 49, in get
tools_awx_1       |     import time; time.sleep(100)
tools_awx_1       |   File "/var/lib/awx/venv/awx/lib64/python3.11/site-packages/ansible_base/lib/middleware/logging/log_request.py", line 19, in handle_signal
tools_awx_1       |     path: {request.path} while in stack: {''.join(traceback.format_stack())}
tools_awx_1       | 

@kdelee kdelee force-pushed the timeout_traceback_middleware branch from 9ceba08 to cd45969 Compare August 27, 2024 14:13
uwsgi 2.0.22+ offers option to send a user-defined signal at for a
"graceful" timeout before the real harakiri occurs.

gunicorn sends SIGABRT (signal 6) as graceful timeout signal before
sending SIGKILL

Apps can use this middleware to log a traceback indicating what code was
executing when the graceful timeout signal was received.

log error message if trying to use middleware in incompatible environment
@kdelee kdelee force-pushed the timeout_traceback_middleware branch from cd45969 to a56bdee Compare August 27, 2024 16:29
Copy link

@mabashian mabashian merged commit 21c6526 into ansible:devel Aug 27, 2024
11 checks passed
@kdelee kdelee deleted the timeout_traceback_middleware branch August 27, 2024 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants