Home  >  Article  >  Backend Development  >  How Can I Gracefully Cancel Goroutines After a Specified Time Limit in Go?

How Can I Gracefully Cancel Goroutines After a Specified Time Limit in Go?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-11-19 19:25:03747browse

How Can I Gracefully Cancel Goroutines After a Specified Time Limit in Go?

Canceling Goroutines after a Time Limit

In load testing scenarios, controlling the execution duration of Goroutines is crucial. Here's an effective approach to achieve this.

Consider the following code snippet that manages HTTP requests in Goroutines:

func attack(cfg AttackConfig) {
    // some code ...

    var ar attackResponse
    ch := make(chan uint8, 8)

    go func() {
        time.Sleep(cfg.Duration * time.Second)
        ch <- CALL_TIME_RAN_OUT
    }()

    for {
        if atomic.LoadInt32(&currConnections) < atomic.LoadInt32(&maxConnections) - 1 {
            go httpPost(cfg, &ar, ch)
        }

        switch <-ch {
        // some other cases ...
        case CALL_TIME_RAN_OUT:
            fmt.Printf("%d seconds have elapsed. Shutting down!", cfg.Duration)
            return
        }
    }
}

However, Goroutines from httpPost() continue running after the specified cfg.Duration has elapsed.

To address this issue, you can leverage Go's context package. By passing a context.Context object to your Goroutines, you can cancel those Goroutines when the specified timeout is reached.

Here's a revised version of your code using the context package:

import (
    "context"
    "fmt"
    "golang.org/x/net/context"
    "time"
)

func attack(cfg AttackConfig) {
    // some code ...

    var ar attackResponse

    // Define a timeout context
    ctx, cancel := context.WithTimeout(context.Background(), cfg.Duration*time.Second)
    defer cancel()

    go func() {
        time.Sleep(cfg.Duration * time.Second)
        cancel()
    }()

    for {
        if atomic.LoadInt32(&currConnections) < atomic.LoadInt32(&maxConnections) - 1 {
            go httpPost(ctx, cfg, &ar)
        }

        select {
        // some other cases ...
        case <-ctx.Done():
            fmt.Printf("%d seconds have elapsed. Shutting down!", cfg.Duration)
            return
        }
    }
}

func httpPost(ctx context.Context, cfg AttackConfig, a *attackResponse) {
    // some code here to create HTTP client ...

    for {
        // some code to make HTTP call ...

        select {
        case <-ctx.Done():
            return
        default:
        }
    }
}

With this modification, when the specified cfg.Duration expires, the ctx.Done() channel is closed, signaling the cancellation of the httpPost() Goroutines, which will then return.

The above is the detailed content of How Can I Gracefully Cancel Goroutines After a Specified Time Limit in Go?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn