# How CasaOS Implements the Singleflight Pattern to Prevent Duplicate Requests

> Discover how CasaOS uses a custom singleflight package with mutex and WaitGroup to deduplicate identical requests, ensuring expensive functions run only once.

- Repository: [IceWhale/CasaOS](https://github.com/IceWhaleTech/CasaOS)
- Tags: internals
- Published: 2026-06-26

---

**CasaOS prevents duplicate concurrent requests by shipping a custom generic `singleflight` package that deduplicates identical in-flight operations using a mutex-protected map and `sync.WaitGroup`, ensuring expensive functions execute exactly once regardless of how many goroutines request them.**

CasaOS implements request deduplication through its own **singleflight** package located at [`pkg/singleflight/singleflight.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/singleflight/singleflight.go), a generic Go solution that suppresses redundant executions while multiple goroutines wait for a single result. This implementation leverages Go 1.18+ generics to support any result type `T`, eliminating thundering herd problems in device discovery and metadata caching subsystems.

## Singleflight Pattern Architecture

The singleflight implementation centers on the `Group[T]` type, a generic container that tracks in-flight function calls and ensures only one execution occurs per unique key.

### The Group Type

The `Group[T]` struct maintains thread-safe state using a mutex-protected map:

```go
type Group[T any] struct {
    mu sync.Mutex          // protects the map of in‑flight calls
    m  map[string]*call[T] // key → call state
}

```

The map stores `*call[T]` pointers keyed by string identifiers, where each `call` represents an active or completed operation. When goroutines invoke `Do` or `DoChan` with the same key, the group coordinates execution through this centralized state.

### Duplicate Detection and Execution Logic

When `Do` receives a request, it follows a strict coordination protocol:

- **Duplicate detection** – If `g.m[key]` exists, the caller increments `c.dups`, releases the mutex, and blocks on `c.wg.Wait()`.
- **Single execution** – If the key is new, the group creates a fresh `call[T]`, increments the wait-group, and executes the function `fn` exactly once via `g.doCall`.

The `call[T]` struct stores the result values (`val`, `err`), a duplicate counter, and channels awaiting results. After `doCall` completes the original function, a deferred cleanup routine marks the call done with `c.wg.Done()`, removes the map entry (unless `Forget` was invoked), and broadcasts results to all waiting channels.

## Implementing Request Deduplication in CasaOS

CasaOS utilizes the singleflight pattern anywhere expensive operations might coincide, such as network queries or filesystem scans. The generic API allows any subsystem to instantiate a typed `Group` for its specific data requirements.

### Synchronous Deduplication with Do

For blocking operations like device metadata retrieval, CasaOS uses `Group.Do` to ensure only one backend request occurs:

```go
import "github.com/IceWhaleTech/CasaOS/pkg/singleflight"

var deviceInfoSF singleflight.Group[*DeviceInfo]

func GetDeviceInfo(deviceID string) (*DeviceInfo, error) {
    v, err, _ := deviceInfoSF.Do(deviceID, func() (*DeviceInfo, error) {
        return fetchDeviceInfoFromBackend(deviceID)
    })
    return v, err
}

```

If multiple goroutines call `GetDeviceInfo("123")` simultaneously, only the first executes `fetchDeviceInfoFromBackend`. All others block on the internal `WaitGroup` and receive the same `*DeviceInfo` result without triggering additional network requests.

### Asynchronous Operations with DoChan

For non-blocking scenarios like filesystem scanning, `DoChan` returns a channel that receives the result once execution completes:

```go
var scanSF singleflight.Group[*ScanResult]

func ScanDirectory(path string) <-chan singleflight.Result[*ScanResult] {
    return scanSF.DoChan(path, func() (*ScanResult, error) {
        return runDeepScan(path)
    })
}

```

The returned channel receives a `Result[*ScanResult]` containing the scanned data, any error, and a `Shared` flag. This flag indicates whether multiple callers shared the result, helping callers determine if deduplication occurred.

## Real-World Usage of the Singleflight Pattern

CasaOS applies the singleflight pattern in several subsystems to prevent redundant work:

- **[`pkg/device/discovery.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/device/discovery.go)** – Uses `singleflight.Group` to coalesce concurrent device-metadata fetches, preventing duplicate discovery packets.
- **[`pkg/cache/metadata.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/cache/metadata.go)** – Applies the pattern when reading metadata from external services, ensuring only one request hits the backend per resource.
- **[`pkg/scan/scan.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/scan/scan.go)** – Demonstrates the `DoChan` API for deduplicated filesystem scans when multiple requests target the same directory.

## Summary

- CasaOS ships a custom **singleflight** package at [`pkg/singleflight/singleflight.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/singleflight/singleflight.go) using Go 1.18+ generics for type-safe deduplication.
- The **`Group[T]`** type coordinates execution through a mutex-protected map and `sync.WaitGroup`, blocking duplicate callers while a single goroutine executes the function.
- **`Do`** provides synchronous deduplication suitable for database or network queries, while **`DoChan`** enables asynchronous result retrieval for long-running operations.
- The pattern prevents thundering herd issues in subsystems like device discovery and metadata caching by ensuring expensive operations execute exactly once per unique key.

## Frequently Asked Questions

### What is the singleflight pattern?

The singleflight pattern is a concurrency mechanism that prevents multiple goroutines from executing the same expensive operation simultaneously. When several requests arrive for the same resource, only the first executes the function while others wait; upon completion, all waiting goroutines receive the same result, eliminating redundant computations and network calls.

### Why did CasaOS implement its own singleflight instead of using the standard library?

CasaOS created a custom implementation to leverage **Go 1.18+ generics**, whereas the standard `golang.org/x/sync/singleflight` package uses `interface{}` return types requiring type assertions. The CasaOS version allows compile-time type safety with `Group[T]`, letting developers specify exact result types like `*DeviceInfo` or `*ScanResult` rather than generic empty interfaces.

### How does CasaOS handle concurrent requests for the same key?

When concurrent requests arrive with identical keys, the first caller acquires the mutex, creates a `call[T]` entry in the map, and executes the function. Subsequent callers find the existing entry, increment a duplicate counter, release the lock, and block on `c.wg.Wait()`. After the original completes, deferred logic signals the wait-group and broadcasts the result to all waiting goroutines.

### Where can I find examples of singleflight usage in CasaOS?

Production examples appear in [`pkg/device/discovery.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/device/discovery.go) for device metadata deduplication, [`pkg/cache/metadata.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/cache/metadata.go) for external service request coalescing, and [`pkg/scan/scan.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/scan/scan.go) for filesystem scan deduplication. Each file instantiates a `singleflight.Group` with a specific type parameter suited to its data requirements.