Handling Timeouts in Golang: A practical example

Dipto Chakrabarty
3 min readOct 30, 2024

--

Operating with concurrency there are going to be situations where we need to consider a timeout because some process has not occurred and want to execute some logic in such a situation.

Timeouts are useful because you get to handle heartbeats, batch processing and even more practical uses.

So how can we handle timeout in golang.

Well there are a couple of ways to do it.

If you find this article useful please consider giving a few claps and subscribing to encourage me to write better articles.

Using time.After

This is a simple method where we can run a function after some time period using the time module.

select {
case <-time.After(5 * time.Second):
fmt.Println("Operation timed out")
case result := <-resultChan:
fmt.Println("Received result:", result)
}

After 5 seconds the first case runs and Operation timed out comes on screen.

The time.AfterFunc

This is a cool method where we define what function we wish to run after a specified duration of time.

timer := time.AfterFunc(5*time.Second, func() {
fmt.Println("Timeout occurred")
// Cancel the operation or take other actions
})
defer timer.Stop()

After 5 seconds the function executes.

Using time.Ticker

We use a channel where it sends values at regular intervals

ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()

for {
select {
case <-ticker.C:
fmt.Println("Tick")
case <-doneChan:
return
}
}

When we define the ticker it means after every 1 second it sends some value to the channel so the first case is triggered then. This is super useful in case we wish to do heartbeats.

A simple Example

Lets run a simple example which shows how they work.

package main

import (
"fmt"
"math/rand"
"time"
)

// Function to execute on timeout
func Reload() {
fmt.Println("Executed function on timeout")
}

// Function to simulate timeout using time.After
func timeoutWithAfter() {
start := time.Now()
timeoutDuration := time.Duration(150+rand.Intn(150)) * time.Millisecond
fmt.Printf("\ntime.After timeout duration: %v\n", timeoutDuration)

select {
case <-time.After(timeoutDuration):
fmt.Printf("Elapsed time with time.After: %v\n", time.Since(start))
Reload()
}
}

// Function to simulate timeout using time.AfterFunc
func timeoutWithAfterFunc() {
start := time.Now()
timeoutDuration := time.Duration(150+rand.Intn(150)) * time.Millisecond
fmt.Printf("\ntime.AfterFunc timeout duration: %v\n", timeoutDuration)

time.AfterFunc(timeoutDuration, func() {
fmt.Printf("Elapsed time with time.AfterFunc: %v\n", time.Since(start))
Reload()
})

// Prevent main from exiting immediately
time.Sleep(timeoutDuration + 50*time.Millisecond)
}

// Function to simulate timeout using time.Ticker
func timeoutWithTicker() {
start := time.Now()
timeoutDuration := time.Duration(150+rand.Intn(150)) * time.Millisecond
fmt.Printf("\ntime.Ticker timeout duration: %v\n", timeoutDuration)

ticker := time.NewTicker(timeoutDuration)
defer ticker.Stop()

select {
case <-ticker.C:
fmt.Printf("Elapsed time with time.Ticker: %v\n", time.Since(start))
Reload()
}
}

// Main function to run all timeout methods
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println("Starting the timeout demonstrations...\n")

// Demonstrate timeout using time.After
timeoutWithAfter()

// Demonstrate timeout using time.AfterFunc
timeoutWithAfterFunc()

// Demonstrate timeout using time.Ticker
timeoutWithTicker()

fmt.Println("All timeout demonstrations complete.")
}

On running this we can see

It shows the timeout value we have configured and exactly how much time later the function executes.

Like such content , follow for more.

--

--

Dipto Chakrabarty
Dipto Chakrabarty

Written by Dipto Chakrabarty

MS @CMU , Site Reliability Engineer , I talk about Cloud Distributed Systems. Tech Doctor making sure to diagnose and make your apps run smoothly in production.

No responses yet