leonklingele adcf92dec1
🚀 Feature: Add idempotency middleware (v2 backport) (#2288)
* 🚀 Feature: Add idempotency middleware (#2253)

* middleware: add idempotency middleware

* middleware/idempotency: use fiber.Storage instead of custom storage

* middleware/idempotency: only allocate data if really required

* middleware/idempotency: marshal response using msgp

* middleware/idempotency: add msgp tests

* middleware/idempotency: do not export response

* middleware/idempotency: disable msgp's -io option to disable generating unused methods

* middleware/idempotency: switch to time.Duration based app.Test

* middleware/idempotency: only create closure once

* middleware/idempotency: add benchmarks

* middleware/idempotency: optimize strings.ToLower when making comparison

The real "strings.ToLower" still needs to be used when storing the data.

* middleware/idempotency: safe-copy body

* middleware/idempotency: backport to v2
2023-01-13 08:38:50 +01:00

54 lines
763 B
Go

package idempotency
import (
"sync"
)
// Locker implements a spinlock for a string key.
type Locker interface {
Lock(key string) error
Unlock(key string) error
}
type MemoryLock struct {
mu sync.Mutex
keys map[string]*sync.Mutex
}
func (l *MemoryLock) Lock(key string) error {
l.mu.Lock()
mu, ok := l.keys[key]
if !ok {
mu = new(sync.Mutex)
l.keys[key] = mu
}
l.mu.Unlock()
mu.Lock()
return nil
}
func (l *MemoryLock) Unlock(key string) error {
l.mu.Lock()
mu, ok := l.keys[key]
l.mu.Unlock()
if !ok {
// This happens if we try to unlock an unknown key
return nil
}
mu.Unlock()
return nil
}
func NewMemoryLock() *MemoryLock {
return &MemoryLock{
keys: make(map[string]*sync.Mutex),
}
}
var _ Locker = (*MemoryLock)(nil)