In this article, we will see how to use the Context package to set a timeout, and how this can be used to manage concurrent processes in Golang.

Context is a powerful package & the ability to establish a timeout on a context is one of the most useful features of the Context package. This enables us to limit the amount of time a process is allowed to run and properly handle the process’s output.

Setting a Timeout on a Context

To set a timeout on a context, we can use the context.WithTimeout function. This function takes an existing context and a duration, and returns a new context that has a timeout set.

Here is an example:

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    defer cancel()

    select {
    case <-time.After(5 * time.Second):
        fmt.Println("Slow process completed")
    case <-ctx.Done():
        fmt.Println("Process timed out")
    }
}

Explanation:

In the above example, we have created a new context using the context.Background() function. We then call context.WithTimeout to create a new context that has a timeout of 3 seconds. We also call defer cancel() to ensure that the context is cancelled when the function returns.

We used select statement to wait for one of two events to occur. If a slow process completes within 5 seconds, the first case will be executed and “Slow process completed” will be printed. If the process takes longer than 3 seconds, the second case will be executed and “Process timed out” will be printed.

Handling a Timed-Out Process

In the previous example, we simply print a message when the process times out. However, in a real-world application, we would likely need to handle the timed-out process more gracefully. For example, we might need to clean up resources, or return an error to the user.

To handle a timed-out process, we can check the value of ctx.Err(). If the context timed out, the error value will be set to context.DeadlineExceeded.

Here is an example:

package main

import (
    "context"
    "fmt"
    "time"
)

func slowProcess(ctx context.Context) error {
    // Do some slow work here
    time.Sleep(5 * time.Second)

    // Check if the context timed out
    if ctx.Err() == context.DeadlineExceeded {
        return fmt.Errorf("process timed out")
    }

    // Return the result of the process
    return nil
}

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    defer cancel()

    if err := slowProcess(ctx); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("Slow process completed successfully")
    }
}

In the above example, we define a slowProcess function that does some slow work (in this case, sleeping for 5 seconds). We check the value of ctx.Err() after the slow work is done, and return an error if the context timed out.

In the main function, we call slowProcess with the context that has a timeout set. If the process time out then we print an error message. If the process completes successfully, we print a success message.

Categorized in:

Tagged in: