Timeout

原文: https://docs.gofiber.io/api/middleware/timeout

Timeout 超时

There exist two distinct implementations of timeout middleware Fiber.

​ 存在两种不同的 Fiber 超时中间件实现。

New

Wraps a fiber.Handler with a timeout. If the handler takes longer than the given duration to return, the timeout error is set and forwarded to the centralized ErrorHandler.

​ 用超时包装 fiber.Handler 。如果处理器花费的时间超过给定的持续时间才返回值,则会设定超时并将其转发到集中式 ErrorHandler。

CAUTION 注意

This has been deprecated since it raises race conditions.

​ 此方法已弃用,因为它会产生竞争状况。

NewWithContext

As a fiber.Handler wrapper, it creates a context with context.WithTimeout and pass it in UserContext.

​ 作为一个 fiber.Handler 包装器,它会创建一个包含 context.WithTimeout 的上下文,并将其传递给 UserContext 。

If the context passed executions (eg. DB ops, Http calls) takes longer than the given duration to return, the timeout error is set and forwarded to the centralized ErrorHandler.

​ 如果传递的上下文(例如,数据库运算、Http 调用)花费的时间超过给定的持续时间才返回值,则会设定超时并将其转发到集中式 ErrorHandler 。

It does not cancel long running executions. Underlying executions must handle timeout by using context.Context parameter.

​ 它不取消长时间运行的任务。基础层级必需使用 context.Context 参数来进行超时管理。

Signatures 签名

1
2
func New(handler fiber.Handler, timeout time.Duration, timeoutErrors ...error) fiber.Handler
func NewWithContext(handler fiber.Handler, timeout time.Duration, timeoutErrors ...error) fiber.Handler

Examples 示例

Import the middleware package that is part of the Fiber web framework

​ 导入 Fiber Web 框架的一部分中间件包

1
2
3
4
import (
  "github.com/gofiber/fiber/v2"
  "github.com/gofiber/fiber/v2/middleware/timeout"
)

After you initiate your Fiber app, you can use the following possibilities:

​ 在启动 Fiber 应用后,您可以使用以下可能性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func main() {
    app := fiber.New()

    h := func(c *fiber.Ctx) error {
        sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
        if err := sleepWithContext(c.UserContext(), sleepTime); err != nil {
            return fmt.Errorf("%w: execution error", err)
        }
        return nil
    }

    app.Get("/foo/:sleepTime", timeout.New(h, 2*time.Second))
    log.Fatal(app.Listen(":3000"))
}

func sleepWithContext(ctx context.Context, d time.Duration) error {
    timer := time.NewTimer(d)

    select {
    case <-ctx.Done():
        if !timer.Stop() {
            <-timer.C
        }
        return context.DeadlineExceeded
    case <-timer.C:
    }
    return nil
}

Test http 200 with curl:

​ 使用 curl 测试 http 200:

1
curl --location -I --request GET 'http://localhost:3000/foo/1000' 

Test http 408 with curl:

​ 使用 curl 测试 http 408:

1
curl --location -I --request GET 'http://localhost:3000/foo/3000' 

Use with custom error:

​ 使用自定义的异常:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var ErrFooTimeOut = errors.New("foo context canceled")

func main() {
    app := fiber.New()
    h := func(c *fiber.Ctx) error {
        sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
        if err := sleepWithContextWithCustomError(c.UserContext(), sleepTime); err != nil {
            return fmt.Errorf("%w: execution error", err)
        }
        return nil
    }

    app.Get("/foo/:sleepTime", timeout.NewWithContext(h, 2*time.Second, ErrFooTimeOut))
    log.Fatal(app.Listen(":3000"))
}

func sleepWithContextWithCustomError(ctx context.Context, d time.Duration) error {
    timer := time.NewTimer(d)
    select {
    case <-ctx.Done():
        if !timer.Stop() {
            <-timer.C
        }
        return ErrFooTimeOut
    case <-timer.C:
    }
    return nil
}

Sample usage with a DB call:

​ 使用数据库调用的示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func main() {
    app := fiber.New()
    db, _ := gorm.Open(postgres.Open("postgres://localhost/foodb"), &gorm.Config{})

    handler := func(ctx *fiber.Ctx) error {
        tran := db.WithContext(ctx.UserContext()).Begin()
        
        if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil {
            return tran.Error
        }
        
        if tran = tran.Commit(); tran.Error != nil {
            return tran.Error
        }

        return nil
    }

    app.Get("/foo", timeout.NewWithContext(handler, 10*time.Second))
    log.Fatal(app.Listen(":3000"))
}
最后修改 October 10, 2024: 更新 (a4b8f854)