timer.go 1.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. package router
  2. import (
  3. "context"
  4. "fmt"
  5. "net/http"
  6. "time"
  7. "github.com/imgproxy/imgproxy/v3/config"
  8. "github.com/imgproxy/imgproxy/v3/ierrors"
  9. )
  10. type timerSinceCtxKey = struct{}
  11. func startRequestTimer(r *http.Request) (*http.Request, context.CancelFunc) {
  12. ctx := r.Context()
  13. ctx = context.WithValue(ctx, timerSinceCtxKey{}, time.Now())
  14. ctx, cancel := context.WithTimeout(ctx, time.Duration(config.WriteTimeout)*time.Second)
  15. return r.WithContext(ctx), cancel
  16. }
  17. func ctxTime(ctx context.Context) time.Duration {
  18. if t, ok := ctx.Value(timerSinceCtxKey{}).(time.Time); ok {
  19. return time.Since(t)
  20. }
  21. return 0
  22. }
  23. func CheckTimeout(ctx context.Context) error {
  24. select {
  25. case <-ctx.Done():
  26. d := ctxTime(ctx)
  27. err := ctx.Err()
  28. switch err {
  29. case context.Canceled:
  30. return ierrors.New(499, fmt.Sprintf("Request was cancelled after %v", d), "Cancelled")
  31. case context.DeadlineExceeded:
  32. return ierrors.New(http.StatusServiceUnavailable, fmt.Sprintf("Request was timed out after %v", d), "Timeout")
  33. default:
  34. return err
  35. }
  36. default:
  37. return nil
  38. }
  39. }