Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何通过依赖注入 wire 后台作业? #916

Closed
MarsonShine opened this issue May 17, 2021 · 8 comments
Closed

如何通过依赖注入 wire 后台作业? #916

MarsonShine opened this issue May 17, 2021 · 8 comments
Labels
question Further information is requested

Comments

@MarsonShine
Copy link

首先作业是在应用层之上的,就是说具体的 worker 是直接依赖于 service 层的 api 方法(当然依赖 biz 也行)
而 internal 内部的初始化都是通过 wire 依赖注入自动生成的。所以这就导致了 worker 也必须要依赖于 wire。

我通过目前的 kratos(beta-3) 的结构,我在 internal 内部增加了 worker 层,位于 service 之上。那么目前我的项目结构就变成了

internal  
	biz
	conf
	data
	server
	service
	worker

按照现有的模式,我将代码改成如下形式,想利用已有的 wire 完成自动注入

// internal / worker / worker.go

package worker

import (
	"github.com/google/wire"
)

// ProviderSet is service providers.
var ProviderSet = wire.NewSet(NewExampleWorker)

type Job interface {
	Handle()
}

具体的 worker

// internal / worker / example.go

package worker

import (
	"Example/internal/biz"
	"time"

	"github.com/go-co-op/gocron"
	"github.com/go-kratos/kratos/v2/log"
)

type mergeClassWorker struct {
	service service.ExampleService
	log   *log.Helper
	job   *gocron.Scheduler
}

func NewExampleWorker(example service.ExampleService, logger log.Logger) Job {
	scheduler := gocron.NewScheduler(time.UTC)
	return &mergeClassWorker{
		service: example,
		job:   scheduler,
		log:   log.NewHelper("job/example", logger),
	}
}

func (worker *mergeClassWorker) Handle() {
	worker.job.Every(5).Second().Do(func() {
		worker.service.DoMyWork()
	})
	worker.job.StartAsync()
}

那么 wire.go 我添加了如下代码

package main
... // 省略部分代码
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {
	panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, worker.ProviderSet, wokerStartup,newApp))
}

按照 newApp 依葫芦画瓢在 main.go 创建一个 wokerStartup 方法

func wokerStartup(jobs ...worker.Job) {
	for i := 0; i < len(jobs); i++ {
		jobs[i].Handle()
	}
}

实际上这样是行不通的,先不说 wire 支不支持将多个 worker.Job 类型合并为数组。在执行依赖注入的时候,编译器报 no signature help: cannot find an enclosing function,应该是没有写 clean 方法,所以是不符合 wire 生成规则。那么这样就要结合 *kratos.App 这个类型做文章。到这里就进行不下去了

请问,目前是否有一种方式能实现到我这种目的,程序已启动就能根据注册的 worker 自启动。

@MarsonShine MarsonShine added the question Further information is requested label May 17, 2021
@MarsonShine MarsonShine changed the title 如何通过依赖注入 wire 后台作业?[Question] 如何通过依赖注入 wire 后台作业? May 17, 2021
@miyabyte
Copy link
Contributor

miyabyte commented Jun 3, 2021

kratos的server只需实现:

type Server interface {
	Endpoint() (string, error)
	Start() error
	Stop() error
}

然后依赖上:

func newApp(Job) {
      ...
               kratos.Server(
			hs,
			gs,
			//Job
		),

这样可以么 :)
还可以在注册中心看到 :)

@onnoink
Copy link

onnoink commented Jun 4, 2021

需要一个新的interface

type Worker interface {
       Start() error
       Stop() error
}

和一个新的options.go还有对应的方法

func Workder(worker ...transport.Workder) Option {
     return func(o *options) { o.wokrder = srv }
}

@MarsonShine
Copy link
Author

@novliang @miyabyte 谢谢回复

需要一个新的interface

type Worker interface {
       Start() error
       Stop() error
}

和一个新的options.go还有对应的方法

func Workder(worker ...transport.Workder) Option {
     return func(o *options) { o.wokrder = srv }
}

这种方式我尝试过,wire 还是生成不了,只不过我是 Job 接口

@goxiaoy
Copy link

goxiaoy commented Aug 30, 2021

package main
... // 省略部分代码
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {
	panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, worker.ProviderSet, wokerStartup,newApp))
}

改成

package main
... // 省略部分代码
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, log.Logger, ...worker.Job) (*kratos.App, func(), error) {
	panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, worker.ProviderSet, wokerStartup,newApp))
}

initApp的时候把job加进去

@MarsonShine
Copy link
Author

MarsonShine commented Sep 3, 2021

package main
... // 省略部分代码
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {
	panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, worker.ProviderSet, wokerStartup,newApp))
}

改成

package main
... // 省略部分代码
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, log.Logger, ...worker.Job) (*kratos.App, func(), error) {
	panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, worker.ProviderSet, wokerStartup,newApp))
}

initApp的时候把job加进去

这样就相当于把 worker 当作顶层应用设计了,因而就无法重用 application -> repository 的代码逻辑了。是不符合现有结构理念的

@goxiaoy
Copy link

goxiaoy commented Sep 3, 2021

package main
... // 省略部分代码
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {
	panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, worker.ProviderSet, wokerStartup,newApp))
}

改成

package main
... // 省略部分代码
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, log.Logger, ...worker.Job) (*kratos.App, func(), error) {
	panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, worker.ProviderSet, wokerStartup,newApp))
}

initApp的时候把job加进去

这样就相当于把 worker 当作顶层应用设计了,因而就无法重用 application -> repository 的代码逻辑了。是不符合现有结构理念的

顶层依赖Worker,没问题呀。 你把work放在该放在的地方,不明白为什么不能重用,又没有循环依赖

@goxiaoy
Copy link

goxiaoy commented Sep 4, 2021

@MarsonShine 你是要用依赖注入对吧

func wokerStartup(jobs ...worker.Job) {
	for i := 0; i < len(jobs); i++ {
		jobs[i].Handle()
	}
}

这个改成具体的Job就好了

func wokerStartup(job 1 worker.JobA, job 2 worker.Job2) {
        jobs := []worker.Job[]{ job1, job2}
	for i := 0; i < len(jobs); i++ {
		jobs[i].Handle()
	}
}

如果你这个workerStartup比较复杂,需要复用,使用Option pattern

新建一个

type WorkerOption struct{
    Jobs []worker.Job
}

然后wokerStartup依赖于这个WorkerOption. NewWorkerOption依赖于具体的Job

@daemon365
Copy link
Member

四个月过去了 如果有问题请 reopen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants