1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2024-11-24 08:12:38 +02:00

Proper semaphore

This commit is contained in:
DarthSim 2022-07-20 18:06:26 +06:00
parent 20039f49a5
commit 526724105e
2 changed files with 53 additions and 6 deletions

View File

@ -23,18 +23,19 @@ import (
"github.com/imgproxy/imgproxy/v3/processing" "github.com/imgproxy/imgproxy/v3/processing"
"github.com/imgproxy/imgproxy/v3/router" "github.com/imgproxy/imgproxy/v3/router"
"github.com/imgproxy/imgproxy/v3/security" "github.com/imgproxy/imgproxy/v3/security"
"github.com/imgproxy/imgproxy/v3/semaphore"
"github.com/imgproxy/imgproxy/v3/svg" "github.com/imgproxy/imgproxy/v3/svg"
"github.com/imgproxy/imgproxy/v3/vips" "github.com/imgproxy/imgproxy/v3/vips"
) )
var ( var (
processingSem chan struct{} processingSem *semaphore.Semaphore
headerVaryValue string headerVaryValue string
) )
func initProcessingHandler() { func initProcessingHandler() {
processingSem = make(chan struct{}, config.Concurrency) processingSem = semaphore.New(config.Concurrency)
vary := make([]string, 0) vary := make([]string, 0)
@ -235,15 +236,14 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
} }
// The heavy part start here, so we need to restrict concurrency // The heavy part start here, so we need to restrict concurrency
select { processingSemToken, aquired := processingSem.Aquire(ctx)
case processingSem <- struct{}{}: if !aquired {
case <-ctx.Done():
// We don't actually need to check timeout here, // We don't actually need to check timeout here,
// but it's an easy way to check if this is an actual timeout // but it's an easy way to check if this is an actual timeout
// or the request was cancelled // or the request was cancelled
checkErr(ctx, "queue", router.CheckTimeout(ctx)) checkErr(ctx, "queue", router.CheckTimeout(ctx))
} }
defer func() { <-processingSem }() defer processingSemToken.Release()
statusCode := http.StatusOK statusCode := http.StatusOK

47
semaphore/semaphore.go Normal file
View File

@ -0,0 +1,47 @@
package semaphore
import (
"context"
"sync"
)
type Semaphore struct {
sem chan struct{}
}
func New(n int) *Semaphore {
return &Semaphore{
sem: make(chan struct{}, n),
}
}
func (s *Semaphore) Aquire(ctx context.Context) (*Token, bool) {
select {
case s.sem <- struct{}{}:
return &Token{release: s.release}, true
case <-ctx.Done():
return &Token{release: func() {}}, false
}
}
func (s *Semaphore) TryAquire() (*Token, bool) {
select {
case s.sem <- struct{}{}:
return &Token{release: s.release}, true
default:
return &Token{release: func() {}}, false
}
}
func (s *Semaphore) release() {
<-s.sem
}
type Token struct {
release func()
releaseOnce sync.Once
}
func (t *Token) Release() {
t.releaseOnce.Do(t.release)
}