我正在try 在我的项目中实施Asynq,这是一个著名的Golang作业(job)调度器,目前我对缺乏有关任务本身内部可能的具体场景的文档感到非常困惑.请注意,互联网上甚至没有任何痕迹,这让我认为我想要解决这个问题的方式可能是非常错误的.

通常,我会在main.go中设置一个数据库连接,并通过依赖项注入与所有内容进行通信.

clients := services.Clients{
  Db:           dbClient,
  Redis:        redisClient,
  // and many more
}

// In my case I use GraphQL to handle requests
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers.Resolver{
  Services: &catalogue, // some services I need to use depending the request
  Clients:  &clients, // here we communicate the database, etc.
}}))

正如您所看到的,我实际上可以将clients传达给我的请求处理程序(解析器),并在那里过上幸福的生活,查询数据库.

设置Asynq时,客户端是这样的

asynqClient := asynq.NewClient(asynq.RedisClientOpt{
  Addr:     os.Getenv("REDIS_ENDPOINT"),
  DB:       0, // will use the default one
  Password: os.Getenv("REDIS_PASSWORD"),
})
defer asynqClient.Close()

tsk, err := tasks.NewPing("pong")
if err != nil {
    fmt.Printf("%s", err)
    panic(err)
}
_, err = asynqClient.Enqueue(tsk)
if err != nil {
    fmt.Printf("%s", err)
    panic(err)
}

我已经在tasks.go中抽象了ping代码

package tasks

import (
    "context"
    "encoding/json"
    "log"

    "github.com/hibiken/asynq"
)

// A list of task types.
const (
    TypePing = "misc:ping"
)

type pingTaskPayload struct {
    Test string
}

func NewPing(test string) (*asynq.Task, error) {
    payload, err := json.Marshal(pingTaskPayload{Test: test})
    if err != nil {
        return nil, err
    }
    return asynq.NewTask(TypePing, payload), nil
}

func HandlePing(ctx context.Context, t *asynq.Task) error {
    var p pingTaskPayload
    if err := json.Unmarshal(t.Payload(), &p); err != nil {
        return err
    }
    log.Printf(" [*] Ping received with arguments: %s", p.Test)
    return nil
}

你指挥它,它会穿过Redis并在另一边被接住.

asynqServer := asynq.NewServer(
  asynq.RedisClientOpt{
    Addr:     os.Getenv("REDIS_ENDPOINT"),
    DB:       0, // will use the default one
    Password: os.Getenv("REDIS_PASSWORD"),
  },
  asynq.Config{Concurrency: 10},
)

mux := asynq.NewServeMux()
mux.HandleFunc(tasks.TypePing, tasks.HandlePing)
go asynqServer.Run(mux)

正如您所看到的,任何地方都没有空间注入任何东西.依赖关系在哪里?为什么它不建议以某种方式将其传达给任务?每个人如何使用它?getting started人从未引用任何依赖性.

理想情况下,我想使用mux.HandleFunc并将一堆客户端(例如DB连接)提供给tasks.HandlePing

目前,我看到的唯一"可行"解决方案是将我的服务器设置为main的全局值,以便从系统中的任何地方获取,这是我不想这样做的.我想要一个明确的依赖注入模式.

如何以干净的方式将我的依赖项(clients个,包括数据库)传达给Asynq?我避免在这里设置全球性是错误的吗?

我已经广泛搜索了几个小时.就像没有人问过自己传递依赖项的问题一样,而且这个库非常有名,所以我可能在某种程度上做错了什么.

推荐答案

嗯,这比我想象的要简单得多,我只需将客户端传递到我创建的Tasks struct 中即可.

# in /tasks/
package tasks

import (
    "aquiestoy/pkg/mailer"
    "aquiestoy/pkg/tracking"

    "github.com/hibiken/asynq"
    "github.com/redis/go-redis/v9"
    "gorm.io/gorm"
)

type Clients struct {
    Db       *gorm.DB
    Redis    *redis.Client
    Tracking *tracking.Tracking
    Mailer   *mailer.Mailer
    Asynq    *asynq.Client
}

type Tasks struct {
    Clients *Clients
}

然后在main.go强中

tsks := tasks.Tasks{
  Clients: &tasks.Clients{
    Db:       dbClient,
    Redis:    redisClient,
    Tracking: tkClient,
    Mailer:   mailClient,
    Asynq:    asynqClient,
  },
}

tsk, err := tsks.NewPing("pong")
if err != nil {
  fmt.Printf("%s", err)
  panic(err)
}
_, err = asynqClient.Enqueue(tsk)
if err != nil {
  fmt.Printf("%s", err)
  panic(err)
}

// NOTE : this should eventually be separated from the client
asynqServer := asynq.NewServer(
  asynq.RedisClientOpt{
    Addr:     os.Getenv("REDIS_ENDPOINT"),
    DB:       0, // will use the default one
    Password: os.Getenv("REDIS_PASSWORD"),
  },
  asynq.Config{Concurrency: 10},
)

mux := asynq.NewServeMux()
mux.HandleFunc(tasks.TypePing, tsks.HandlePing)
go asynqServer.Run(mux)

为了更好的衡量标准,也可以用NewTasks来包装,但这对我来说有效.

Go相关问答推荐

如何预编译Golang标准库?

Golang使用Run()执行的命令没有返回

如何在围棋中从多部分.Part中获取多部分.文件而不保存到磁盘?

使用Golang的Lambda自定义al2运行时,初始化阶段超时

Golang内置打印(Ln)函数&S行为怪异

正确使用pgtype的方法

为什么 `go mod` 占用了另一个磁盘上的空间而不是我的 GOPATH?

Prometheus 摘要分位数错误

如何将 goose 迁移与 pgx 一起使用?

在 GoLang 中对自定义 struct 体数组进行排序

Global Thread-local Storage 在 Go 中的可行性和最佳实践

这是泛型的有效用例吗?

这是实现超时的常见方法,为什么 time.After 不起作用

用于提取 <*n 的正则表达式(其中 n 是一个数字)

我突然无法再将我的 GoLang 应用程序部署到 Google AppEngine

将 struct 转换为 CSV 字符串

确保 Go 1.20 编译时的严格可比性?

使用 Golang SQL 驱动程序连接到snowflake

如何在 Windows 中使用 github.com/AllenDang/giu 和 github.com/gordonklaus/portaudio 构建 GO 程序

如何从 docker-compose 命令运行 2 个不同的命令: