• Writing in the front
  • Applicable people
  • Code-level support for elegant abort is essential
    • The meaning of graceful suspension
    • Termination mechanism for Pod in Kubernetes
    • Examples of gracefully aborted Go code
    • Source code interpretation – elegant abort processing ideas
    • Source code interpretation – a few points of concern
  • summary
  • reference

Writing in the front

As a general design principle, every HTTP request is stateless, so it’s easy for Web applications to scale horizontally in most cases. “Stateless” also means that the cost of initiating HTTP requests for retries is low, making graceful abort less of a concern for Web interface development (in part because Web frameworks do).

However, there will always be interruption-sensitive interfaces (such as payment-related) in the business, and there will always be stateful services, where graceful interrupts are important.

This article uses an example of a Go scheduled task to briefly introduce the idea of handling graceful abort in the Go technology stack.

Applicable people

Beginner √ Intermediate advanced; This article is suitable for beginners and above.

Code-level support for elegant abort is essential

The meaning of graceful suspension

The so-called “graceful abort” means that after receiving a specific abort signal (such as INT and TERM), the application will no longer accept external new requests or create internal new tasks. The application process will continue to run until the old requirements and tasks are completed and then terminate.

Termination mechanism for Pod in Kubernetes

As a highly reliable service platform, K8S defines the basic steps for terminating a Pod (in which a business process runs) : When a POD is actively deleted, the system sends the TERM signal to the main processes in each container before forcing the termination of the POD, and then sends the KILL signal to those processes after a certain amount of time (30 seconds by default). In addition, K8S provides the ability to manage the container lifecycle through hook methods, allowing users to customize the operations performed after the container is started or terminated.

If the application implements the graceful abort mechanism when packaged into images running in K8S, it can take full advantage of the aforementioned K8S capabilities to upgrade applications (release new versions) and manage PODS (move pods to another host while hosting maintenance). Or dynamically shrink the number of PODS at idle to save resources for other uses) to achieve zero interruption of service.

Examples of gracefully aborted Go code

The following code defines two timed tasks: mySecondJobs fires once every second, each lasting about 1 second; MyMinuteJobs triggers once every minute and each time lasts about 2 seconds. Specifically, you can read the following code (you can copy the following code directly to run in your own environment) :

Package main import (" FMT "" OS" "OS /signal" "syscall" "time") func main() {c := make(chan os.signal) // Go SIGKILL and SIGSTOP signals/https://github.com/golang/go/issues/9463 / reference signal. The Notify (c, the syscall SIGINT, syscall.SIGTERM) second := time.NewTicker(time.Second) minute := time.NewTicker(time.Minute) A: For {select {case s := <-c: FMT.Printf(" Get signal %s, gracefulending... \n", s) break A case <-second.C: go mySecondJobs() case <-minute.C: Go myMinuteJobs()}} FMT.Println("graceful ending") 😆 time.sleep (time.second * 10) fmt.println ("graceful ended.")} func mySecondJobs() {tS := time.Now().String() fmt.Printf("starting second job: FMT.Printf(" Second job %s are done. \n", tS) time.sleep (time.second * 1) tS) } func myMinuteJobs() { tS := time.Now().String() fmt.Printf("starting minute job: %s \n", tS) time.sleep (time.second * 2) // Fmt. Printf("minute job %s are done. \n", tS)}Copy the code

Source code interpretation – elegant abort processing ideas

  1. throughsignal.NotifyTo capture a specific signal;
  2. throughfor + selectTo realize the cyclic task, and detect the signal to be captured in the previous step;
  3. If the timer is triggered, the corresponding task is executed.
  4. If the specified signal is found, the system exitsforLoop and take some action to end the asynchronous task.

Source code interpretation – a few points of concern

  1. The code usesgo mySecondJobs()go myMinuteJobs()Asynchronous tasks; The signal cannot be captured synchronously because the main thread is processing the business logic and there is no idle signal capture logic.
  2. Lazy in the source code to take a simple wait to ensure the normal end of asynchronous tasks, non-universal method, the actual development needs to be customized according to the situation.
  3. time.TickerThere are caveats to the use ofselectIf there are more than one branch in a statement at the same time, one branch will be randomly selected to execute, resulting in information loss (as described in the last reference article). However, this code does not trigger this problem, and you can think about why.

summary

By default, the Go application directly exits the main process after receiving the TERM signal. If some process is not finished (for example, no response is returned after receiving an external request, or an internal asynchronous task is not finished), the process will be interrupted abnormally and the quality of service will be affected. By explicitly capturing TERM signals and other signals in your code and sensing the operating system’s processing of the process, you can take proactive steps to gracefully terminate the application process.

With the popularity of K8S, application support for graceful termination at the code level (especially for containerized applications) needs to become a development norm worthy of every developer’s attention, given its standardized management of the process lifecycle.

reference

  • Signal (SIGINT, SIGTERM, etc.)
  • The introduction to Pods on the Kubernetes website includes an introduction to the pod lifecycle
  • Container Lifecycle Hooks – Kubernetes Kubernetes official introduction to Hooks in the Container Lifecycle
  • Gracefully shut down Nginx in Kubernetes – A brief introduction to signaling, the termination process for POD in K8S, and graceful termination of Nginx
  • Golang Signal processing – happy programming
  • Golang’s Signal – Katydid Jun – Blog Garden
  • os/signal: Capturing SIGKILL and SIGSTOP signals is not allowed in GitHub Go
  • Although this example does not trigger, it is important to note the glitch when using time.Ticker
  • How to get a graceful shutdown of an server. · Issue #1329 · GIN-gonic/GIN · GitHub Go Web framework GIN support example of graceful shutdown