0
0
GoHow-ToBeginner · 4 min read

How to Implement Rate Limiter in Go: Simple Guide with Example

In Go, you can implement a rate limiter using time.Ticker to control how often actions happen by sending ticks at fixed intervals. By combining time.Ticker with channels, you can limit the rate of requests or events easily and efficiently.
📐

Syntax

A basic rate limiter in Go uses time.Ticker which sends a signal on a channel at regular intervals. You listen to this channel to allow actions only when a tick arrives.

  • time.NewTicker(duration): creates a ticker that ticks every duration.
  • ticker.C: channel that receives a tick at each interval.
  • Use a for loop with range ticker.C to perform actions at the limited rate.
go
ticker := time.NewTicker(time.Second) // ticks every 1 second
for range ticker.C {
    // perform limited action here
}
💻

Example

This example shows a rate limiter that allows printing a message only once every 500 milliseconds, simulating a controlled request flow.

go
package main

import (
	"fmt"
	"time"
)

func main() {
	ticker := time.NewTicker(500 * time.Millisecond) // tick every 500ms
	defer ticker.Stop()

	for i := 1; i <= 5; i++ {
		<-ticker.C // wait for tick
		fmt.Printf("Request %d processed at %v\n", i, time.Now().Format("15:04:05.000"))
	}
}
Output
Request 1 processed at 12:00:00.500 Request 2 processed at 12:00:01.000 Request 3 processed at 12:00:01.500 Request 4 processed at 12:00:02.000 Request 5 processed at 12:00:02.500
⚠️

Common Pitfalls

Common mistakes when implementing rate limiters in Go include:

  • Not stopping the ticker with ticker.Stop(), which can cause resource leaks.
  • Blocking on ticker channel without timeout or context, causing deadlocks.
  • Using time.Sleep instead of time.Ticker, which is less efficient and less flexible.

Always use defer ticker.Stop() to clean up and consider using select with context for cancellation.

go
package main

import (
	"fmt"
	"time"
)

func main() {
	// Wrong: ticker not stopped
	ticker := time.NewTicker(time.Second)

	for i := 0; i < 3; i++ {
		<-ticker.C
		fmt.Println("Action", i)
	}

	// Missing ticker.Stop() can cause resource leak

	// Right way:
	// ticker := time.NewTicker(time.Second)
	// defer ticker.Stop()
}
📊

Quick Reference

ConceptDescription
time.NewTicker(duration)Creates a ticker that sends ticks at the given interval
ticker.CChannel that receives ticks to trigger actions
ticker.Stop()Stops the ticker to release resources
<-ticker.CWaits for the next tick before proceeding
Use defer ticker.Stop()Ensure ticker is stopped to avoid leaks

Key Takeaways

Use time.Ticker to send ticks at fixed intervals for rate limiting.
Always stop your ticker with defer ticker.Stop() to avoid resource leaks.
Wait on ticker.C channel to control when actions happen.
Avoid blocking indefinitely by using context or select with ticker.
time.Ticker is more efficient and flexible than time.Sleep for rate limiting.