openfaas / python-flask-template

HTTP and Flask-based OpenFaaS templates for Python 3
MIT License
85 stars 86 forks source link

Drain connections for python3-http #68

Open alexellis opened 1 year ago

alexellis commented 1 year ago

Description

Drain connections for python3-http

Motivation and Context

When used with OpenFaaS Standard/Enterprise, the python3-http template's handler will now ignore SIGTERM allowing the watchdog and Kubernetes to handle the shutdown.

When there are ongoing requests, these will be processed before exiting.

When there are no ongoing requests, the function will exit immediately.

How Has This Been Tested?

Tested with OpenFaaS Standard a long running sleep function which went into a Terminating status. The function continued to execute its sleep for the whole duration, whilst the new replica came online and was ready in the meantime.

This is the same approach tested for the golang-http templates.

After:

py-long-7cfd5f7699-swwrd py-long 2023/05/25 10:48:04 SIGTERM: no new connections in 5s
py-long-7cfd5f7699-swwrd py-long 2023/05/25 10:48:04 Removing lock-file : /tmp/.lock
py-long-7cfd5f7699-swwrd py-long 2023/05/25 10:48:04 stderr: Function got SIGTERM, hanging on for up to 10m2s
py-long-7cfd5f7699-swwrd py-long 2023/05/25 10:48:09 No new connections allowed, draining: 0 requests
py-long-7cfd5f7699-swwrd py-long 2023/05/25 10:48:09 Exiting. Active connections: 0

Code for function: https://github.com/alexellis/go-long/blob/master/stack.yml#L32

Types of changes

No harm change but may require a minimum Python 3 version. I was able to execute test code with 3.8, which is the lowest we advertise to support:

python3 --version
Python 3.8.10

Example:

#!/usr/bin/env python
import os
import sys
import signal
import time

def SignalHandler(SignalNumber, Frame):
    timeout = os.getenv("write_timeout")
    sys.stderr.write('Function got SIGTERM, draining for up to: {}\n'.format(timeout))
    sys.stderr.flush()

if __name__ == '__main__':

    signal.signal(signal.SIGTERM, SignalHandler)

    # Simulate HTTP server etc
    time.sleep(500)

The change is being made for Kubiya who needed a graceful drain of long-running functions.

This is not new behaviour and is already used in the Go templates. Over time we will add it to all officially supported templates.

cc @shakedaskayo @koss110 @LucasRoesler

I'll get this merged, if there is feedback, please let me know and I'll be happy to consider making changes from people who are more experienced with Python than myself.

https://github.com/openfaas/golang-http-template/blob/master/template/golang-middleware/main.go#L45

alexellis commented 1 year ago

As per testing on the community call, the function will sleep for a maximum of healthcheck_interval - then exit - when all connections to the watchdog have completed.