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

Signal handlers for SIGINT and SIGTERM are reset to SIG_IGN even when register_sys_signals is disabled #2956

Open
1 task done
jzombi opened this issue Jun 19, 2024 · 2 comments
Labels

Comments

@jzombi
Copy link

jzombi commented Jun 19, 2024

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

My program uses custom signal handlers to terminate the running sanic application and perform other cleanup steps. In earlier sanic versions it worked by running the application with register_sys_signals=False parameter. In the current version it is not working anymore, because the custom signal handler is overwritten by SIG_IGN upon application startup. See:

def _setup_system_signals(
app: Sanic,
run_multiple: bool,
register_sys_signals: bool,
loop: asyncio.AbstractEventLoop,
) -> None: # no cov
signal_func(SIGINT, SIG_IGN)
signal_func(SIGTERM, SIG_IGN)
os.environ["SANIC_WORKER_PROCESS"] = "true"
# Register signals for graceful termination
if register_sys_signals:
if OS_IS_WINDOWS:
ctrlc_workaround_for_windows(app)
else:
for _signal in [SIGINT, SIGTERM]:
loop.add_signal_handler(
_signal, partial(app.stop, terminate=False)
)

According to git blame the behavior changed with this commit: 4499d2c

Code snippet

import os, signal, threading, time

import sanic

def myhandler(signum, frameno):
    print('RECEIVED SIGNAL', signum)

signal.signal(signal.SIGTERM, myhandler)

def periodic_kill():
    for i in range(4):
        print('SENDING SIGNAL', signal.SIGTERM)
        os.kill(os.getpid(), signal.SIGTERM)
        time.sleep(1)
    os.kill(os.getpid(), signal.SIGKILL)

t = threading.Thread(target=periodic_kill, daemon=True)
t.start()

time.sleep(0.5)

app = sanic.Sanic('example')
app.run(host='localhost', port=8765, register_sys_signals=False, single_process=True)

Expected Behavior

Expected output:

SENDING SIGNAL 15
RECEIVED SIGNAL 15
# sanic startup messages
SENDING SIGNAL 15
RECEIVED SIGNAL 15
SENDING SIGNAL 15
RECEIVED SIGNAL 15
SENDING SIGNAL 15
RECEIVED SIGNAL 15
Killed

Actual output: the RECIEVED SIGNAL 15 messages do not appear after sanic startup.

How do you run Sanic?

As a module

Operating System

Linux

Sanic Version

Sanic 23.12.1; Routing 23.12.0

Additional context

No response

@jzombi jzombi added the bug label Jun 19, 2024
@ahopkins
Copy link
Member

What's the use case you are after?

@jzombi
Copy link
Author

jzombi commented Jun 26, 2024

To have different behavior for SIGINT and SIGTERM. I have a complicated application with multiple workers (not sanic workers), each starting its own sanic instance. There is an orchestrator component that manages the workers. The application should terminate nicely when CTRL-C is pressed. The shut-down process is managed by the orchestrator, workers should not terminate themselves on SIGINT.

What is the reason behind forcefully setting SIG_IGN?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants