From 9546c98ce8f5d2dc2ab6b676b49dde4d44e9f759 Mon Sep 17 00:00:00 2001 From: peterstone2017 <12449837+YunchuWang@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:48:56 -0700 Subject: [PATCH 1/3] feat: add sigterm handler to gracefully shutdown worker and log --- azure_functions_worker/logging.py | 3 +++ azure_functions_worker/main.py | 44 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/azure_functions_worker/logging.py b/azure_functions_worker/logging.py index adb5ff294..7a0bbea0c 100644 --- a/azure_functions_worker/logging.py +++ b/azure_functions_worker/logging.py @@ -91,6 +91,9 @@ def enable_console_logging() -> None: if logger and handler: logger.addHandler(handler) +def flush_logger(logger: logging.Logger): + for handler in logger.handlers: + handler.flush() def is_system_log_category(ctg: str) -> bool: """Check if the logging namespace belongs to system logs. Category starts diff --git a/azure_functions_worker/main.py b/azure_functions_worker/main.py index 130e0e9ea..eff874aa9 100644 --- a/azure_functions_worker/main.py +++ b/azure_functions_worker/main.py @@ -47,12 +47,16 @@ def main(): import asyncio + from . import logging from .logging import error_logger, format_exception, logger args = parse_args() logging.setup(log_level=args.log_level, log_destination=args.log_to) + # register sigterm handler + register_sigterm_handler() + logger.info('Starting Azure Functions Python Worker.') logger.info('Worker ID: %s, Request ID: %s, Host Address: %s:%s', args.worker_id, args.request_id, args.host, args.port) @@ -66,6 +70,46 @@ def main(): format_exception(ex))) raise +def register_sigterm_handler(): + import signal + """ + Registers a custom handler for the SIGTERM signal. + + This function will set up a signal handler to intercept the SIGTERM signal, + which is typically sent to gracefully terminate a process. When SIGTERM is + received, the program will log the signal and perform a graceful shutdown + by calling sys.exit(). + + Windows Python Function is not supported and Windows does not support + SIGTERM. + """ + + def handle_sigterm(signum, frame): + from . import dispatcher + import sys + from .logging import logger, flush_logger + import traceback + from azure_functions_worker.dispatcher import DispatcherMeta + from azure_functions_worker import loader + # Log the received signal + logger.info(f"SIGTERM received (signal: {signum}). " + "Shutting down gracefully...") + + # Log the frame details to see whats executed when the signal was received + logger.info("Frame details at signal receipt:" + f"\n{''.join(traceback.format_stack(frame))}") + + DispatcherMeta.__current_dispatcher__ = None + + loader.uninstall() + + flush_logger() + + dispatcher.Dispatcher.stop() + sys.exit(0) # Exit the program gracefully + + signal.signal(signal.SIGTERM, handle_sigterm) + async def start_async(host, port, worker_id, request_id): from . import dispatcher From c31581043fc7914bac44b28b5799122c101355a7 Mon Sep 17 00:00:00 2001 From: peterstone2017 <12449837+YunchuWang@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:50:13 -0700 Subject: [PATCH 2/3] fix: flush_logger --- azure_functions_worker/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_functions_worker/main.py b/azure_functions_worker/main.py index eff874aa9..1738d6d24 100644 --- a/azure_functions_worker/main.py +++ b/azure_functions_worker/main.py @@ -103,7 +103,7 @@ def handle_sigterm(signum, frame): loader.uninstall() - flush_logger() + flush_logger(logger) dispatcher.Dispatcher.stop() sys.exit(0) # Exit the program gracefully From 98f6ac13d23db0919aaec43f59bb53f5ce03265b Mon Sep 17 00:00:00 2001 From: wangbill <12449837+YunchuWang@users.noreply.github.com> Date: Tue, 24 Sep 2024 09:29:46 -0700 Subject: [PATCH 3/3] fix: linting --- azure_functions_worker/logging.py | 2 ++ azure_functions_worker/main.py | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/azure_functions_worker/logging.py b/azure_functions_worker/logging.py index 7a0bbea0c..a7aaae9c3 100644 --- a/azure_functions_worker/logging.py +++ b/azure_functions_worker/logging.py @@ -91,10 +91,12 @@ def enable_console_logging() -> None: if logger and handler: logger.addHandler(handler) + def flush_logger(logger: logging.Logger): for handler in logger.handlers: handler.flush() + def is_system_log_category(ctg: str) -> bool: """Check if the logging namespace belongs to system logs. Category starts with the following name will be treated as system logs. diff --git a/azure_functions_worker/main.py b/azure_functions_worker/main.py index 1738d6d24..b2a7d237d 100644 --- a/azure_functions_worker/main.py +++ b/azure_functions_worker/main.py @@ -47,7 +47,6 @@ def main(): import asyncio - from . import logging from .logging import error_logger, format_exception, logger @@ -70,6 +69,7 @@ def main(): format_exception(ex))) raise + def register_sigterm_handler(): import signal """ @@ -94,10 +94,10 @@ def handle_sigterm(signum, frame): # Log the received signal logger.info(f"SIGTERM received (signal: {signum}). " "Shutting down gracefully...") - + # Log the frame details to see whats executed when the signal was received logger.info("Frame details at signal receipt:" - f"\n{''.join(traceback.format_stack(frame))}") + f"\n{''.join(traceback.format_stack(frame))}") DispatcherMeta.__current_dispatcher__ = None