# How to Implement Request Debouncing Middleware in Gorig: A Complete Guide

> Learn to implement request debouncing middleware in Gorig using its built-in Debounce middleware. Throttle duplicate HTTP requests effectively and prevent overload with this guide.

- Repository: [Jom/gorig](https://github.com/jom-io/gorig)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Gorig provides a built-in `Debounce` middleware in [`httpx/mid.debounce.go`](https://github.com/jom-io/gorig/blob/main/httpx/mid.debounce.go) that uses a sharded request map with automatic cleanup to throttle duplicate HTTP requests within a configurable time window, returning HTTP 429 when limits are exceeded.**

The `jom-io/gorig` framework includes a production-ready request debouncing middleware designed for high-concurrency Gin applications. When you implement request debouncing middleware in Gorig, you leverage a sharded map architecture that minimizes lock contention while automatically managing memory through background cleanup routines.

## Understanding Gorig's Debounce Middleware Architecture

### Sharded Request Map for High Concurrency

At the core of the implementation is the `ShardedRequestMap` structure defined in [`httpx/mid.debounce.go`](https://github.com/jom-io/gorig/blob/main/httpx/mid.debounce.go). This component splits the request tracking storage into **32 independent shards**, each protected by its own `RWMutex`. When a request arrives, Gorig hashes the request key using **FNV-1a** to determine which shard owns the timestamp, dramatically reducing lock granularity under heavy load compared to a single global map.

### Automatic Memory Cleanup

To prevent unbounded memory growth, the middleware spawns a background goroutine that executes every minute. As implemented in [`httpx/mid.debounce.go`](https://github.com/jom-io/gorig/blob/main/httpx/mid.debounce.go), this routine scans each shard and clears the map entirely if the shard's estimated memory consumption exceeds **2 MiB**. This ensures that stale request keys from high-traffic endpoints do not accumulate indefinitely.

### Request Key Generation

The middleware constructs a unique fingerprint for each request using the following logic from [`httpx/mid.debounce.go`](https://github.com/jom-io/gorig/blob/main/httpx/mid.debounce.go):

- **Path and Query**: `path` + `?` + `RawQuery` for GET requests
- **User Identification**: If a JWT token is present, append `:id:` + `userID`; otherwise append `:ip:` + `ClientIP`

This dual strategy ensures authenticated users are throttled independently from anonymous traffic while preventing IP-based collision attacks.

## How to Implement Request Debouncing Middleware in Gorig

### Basic Implementation with Default Settings

Gorig automatically applies debouncing to all routes when you bootstrap the server. In [`httpx/serv.go`](https://github.com/jom-io/gorig/blob/main/httpx/serv.go), the default Gin engine is configured with a **200 millisecond** debounce window:

```go
gEngine.Use(Debounce(200 * time.Millisecond))

```

This single line at line 82 of [`httpx/serv.go`](https://github.com/jom-io/gorig/blob/main/httpx/serv.go) protects your entire API from duplicate submissions without additional configuration.

### Custom Debounce Durations for Specific Routes

For endpoints requiring different throttling behavior, apply the middleware to specific route groups. This overrides the global default for that subtree:

```go
router := gEngine.Group("/api")
router.Use(Debounce(500 * time.Millisecond))
router.GET("/items", itemsHandler)

```

This configuration extends the debounce window to 500ms for all `/api/*` endpoints, accommodating slower client-side polling patterns while maintaining protection.

### Disabling Debounce for Testing

When running integration tests that issue rapid sequential requests, disable the middleware globally to avoid HTTP 429 errors. Call `DebounceDisable()` before initializing test servers:

```go
func TestFastCalls(t *testing.T) {
    httpx.DebounceDisable()
    // ... initialize server and run test code
}

```

This function sets the internal `enable` flag to false, causing the `Debounce` middleware to skip all checks while maintaining handler chain compatibility.

### Whitelisting Specific Endpoints

For health checks, metrics scraping, or other high-frequency legitimate traffic, exclude specific paths from debouncing using `DebouceAw()` (note the spelling as implemented in the source):

```go
func init() {
    httpx.DebouceAw("/health", "/metrics")
}

```

This registers the specified paths in a global whitelist map. When the middleware processes a request, it checks this map before generating the request key, allowing unlimited requests to these endpoints regardless of the debounce window.

## Advanced: Manual Request Key Construction

For custom rate-limiting logic outside the standard middleware, Gorig exposes the key generation algorithm. Replicate the fingerprinting logic to interact with the sharded map directly:

```go
func myHandler(c *gin.Context) {
    token := httpx.GetTokenByCtx(c, false)
    userID := httpx.GetUserIDByToken(token)

    key := c.Request.URL.Path
    if c.Request.Method == "GET" {
        key += "?" + c.Request.URL.RawQuery
    }
    if userID != "" {
        key += ":id:" + userID
    } else {
        key += ":ip:" + c.ClientIP()
    }
    
    // Access the sharded map for custom logic
    shard := httpx.NewShardedRequestMap()
    // ... custom implementation
}

```

This pattern allows you to extend the debounce concept to WebSocket connections, gRPC streams, or other non-HTTP contexts while maintaining consistency with Gorig's core architecture.

## Summary

- **Gorig's debounce middleware** is implemented in [`httpx/mid.debounce.go`](https://github.com/jom-io/gorig/blob/main/httpx/mid.debounce.go) and automatically wired into the default Gin engine in [`httpx/serv.go`](https://github.com/jom-io/gorig/blob/main/httpx/serv.go) with a 200ms window.
- **High-concurrency design** uses a 32-sharded map with FNV-1a hashing and per-shard RWMutexes to minimize lock contention.
- **Memory safety** is ensured by a background cleanup routine that clears shards exceeding 2 MiB every minute.
- **Flexible configuration** allows custom durations per route group, global disabling via `DebounceDisable()`, and path whitelisting via `DebouceAw()`.
- **Request fingerprinting** combines path, query, and user ID (or IP for anonymous requests) to create unique throttle keys.

## Frequently Asked Questions

### What is the default debounce duration in Gorig?

The default debounce window is **200 milliseconds**, configured automatically in [`httpx/serv.go`](https://github.com/jom-io/gorig/blob/main/httpx/serv.go) at line 82 where the middleware is applied to the global Gin engine with `Debounce(200 * time.Millisecond)`.

### How does Gorig prevent memory leaks in the debounce middleware?

Gorig implements a **background cleanup goroutine** that executes every minute, scanning all 32 shards of the `ShardedRequestMap`. If a shard's estimated memory consumption exceeds **2 MiB**, the routine clears that shard's map entirely, preventing unbounded growth from stale request timestamps.

### Can I use different debounce intervals for different user groups?

While the middleware does not natively support per-user-group intervals, you can achieve this by creating **separate route groups** and applying different `Debounce(duration)` middleware instances to each group. For example, apply a 500ms window to `/api/premium` routes and a 200ms window to `/api/free` routes.

### What HTTP status code is returned when a request is debounced?

When a duplicate request is detected within the debounce window, Gorig returns **HTTP 429 Too Many Requests** using the `response.ErrorTooManyRequests` function from [`apix/response/response.go`](https://github.com/jom-io/gorig/blob/main/apix/response/response.go).