-
Notifications
You must be signed in to change notification settings - Fork 21
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
长时间运行的任务探查接口 #20
Comments
不需要写文档,你直接写你代码和接口,我大概就能看明白。看不明白的时候,我就会问你的。 |
我理解是不是这样,提供一个一个查询接口,然后这个接口检查任务运行状态【这个任务可以是http任务】,这个时候我们可以要求任务的流程提供者提供一个接口,返回任务执行的状态,假设是running,successed,fail,unknow,然后根据结果做一些事情,这里用hid做幂等就行。 |
是的。 |
目前我们可以简化一下设计,也就是认为调度任务的 HTTP 接口,也可以用来查询任务进度。后面我们可以考虑允许用户提供不同的接口,或者集中提供一个接口查询所有的在它这里调度的任务的进度 |
在部分失败和超时响应的处理上,要考虑用户节点是不是挂了?如果挂了,那当前这个任务是直接终止,等待下一次调度呢,还是让另外的节点立刻去执行? |
暂时还不需要考虑这个问题。等后面我们统一设计容错机制。暂时只需要一个探活,后续我们可以要求节点上报更多数据,或者通过第三方监控来汇总性能数据,执行容错。 |
写了个基本的demo,我不太能理解,现在的task,executor,这2个实体具体的职责范围,可能要明确讨论下, package executor
import (
"context"
"errors"
"github.com/ecodeclub/ecron/internal/storage"
"github.com/ecodeclub/ecron/internal/task"
"log/slog"
"time"
)
// ExecuteTask
// http服务抽象
// 这里需要改造目前的task设计,要抽取出一个类似于taskCfg的存储结构
// 然后这里根据cid和tid,会创建一个新的task,并且生成eid,如果创建失败,则没有eid
// 但是这样设计会有一个问题,即用户创建的是周期执行任务,eid一个会有问题,,所有也可以考虑不提供返回eid
// 提供接口让用户根据此task自己查询eid
func ExecuteTask(cid int64, tid int64, exp map[string]string) int64 {
panic("")
}
// QueryJobByEid
// http服务抽象
// 根据eid目前任务状态,返回一个json
func QueryJobByEid(eid int64) string {
panic("")
}
type CommonStateExecutor struct {
l *HttpExecutor
executionDAO storage.ExecutionDAO
logger *slog.Logger
}
func (s *CommonStateExecutor) Name() string {
return "有状态的" + s.l.Name()
}
// Run 考虑把eid传入ctx,发给job的真正执行方
func (s *CommonStateExecutor) Run(ctx context.Context, t task.Task) error {
// 这里不把eid暴露出去,则只能通过提供接口查询记录表里面的数据获取eid
s.saveExecutors(t.ID, t.Eid, task.ExecStatusStarted)
var eid = t.Eid
var err error = nil
ch := make(chan struct{}, 1)
ticker := time.NewTicker(time.Second * 3)
ctx, cancel := context.WithCancel(ctx)
go func() {
go func() {
err = s.l.Run(ctx, t)
}()
for {
i := 0
select {
// 这里是调用http接口获取状态
case <-ticker.C:
// 这段代码考虑通过封装,暴露成http接口,可以主动上报错误,但是比较麻烦的是ch这个怎么处理
state, rates := getTargetState()
switch state {
case TargetStateRunning:
i = 0
s.updateExecutorRate(t.ID, t.Eid, rates)
case TargetStateFailed:
ch <- struct{}{}
cancel()
return
case TargetStateSucceed:
ch <- struct{}{}
cancel()
return
case TargetStateTimeout:
i++
if i == 3 {
ch <- struct{}{}
cancel()
return
}
default:
ch <- struct{}{}
cancel()
return
}
case <-ctx.Done():
return
}
}
}()
select {
case <-ch:
case <-ctx.Done():
err = ctx.Err()
close(ch)
_ = cancelTarget()
}
defer func() {
switch {
case errors.Is(err, context.DeadlineExceeded):
s.updateExecutor(t.ID, eid, task.ExecStatusDeadlineExceeded)
case errors.Is(err, context.Canceled):
s.updateExecutor(t.ID, eid, task.ExecStatusCancelled)
case err == nil:
s.updateExecutor(t.ID, eid, task.ExecStatusSuccess)
default:
s.updateExecutor(t.ID, eid, task.ExecStatusFailed)
}
}()
return err
}
type TargetState uint8
const (
TargetStateUnknown TargetState = iota
TargetStateRunning
TargetStateSucceed
TargetStateFailed
TargetStateTimeout
)
// todo 抽取成方法放在task上
func getTargetState() (TargetState, uint8) {
return TargetStateSucceed, 0
}
// todo 抽取成方法放在task上
func cancelTarget() error {
panic("")
}
func (s *CommonStateExecutor) GetState(ctx context.Context, tid int64, eid int64) (ExecStatus, error) {
panic(" 从 executionDAO 里查当前任务执行状态")
}
func (s *CommonStateExecutor) saveExecutors(tid int64, eid int64, status task.ExecStatus) {
panic("记录执行记录,返回eid")
}
func (s *CommonStateExecutor) updateExecutor(tid int64, eid int64, status task.ExecStatus) {
panic("更新结果")
}
func (s *CommonStateExecutor) updateExecutorRate(tid int64, eid int64, rate uint8) {
panic("更新结果")
} |
很简单,Scheduler 就是你的老板,你就是 Executor。你的老板只负责安排任务给你,然后你去执行。在任务这里,根据任务的形态引入了不同的实现,比如说 http 任务代表的是任务本身就是一个 http 接口,调度执行就是发一个 http 请求。 Scheduler 只是居中指挥而已。比如说抢占一个任务,挑选合适的执行节点,安排进度追踪这种 |
Scheduler作为调度者,他的职责我觉得是没有异议的
最后附下个人先入为主的观点: |
目前我们支持了 HTTP 接口作为远程任务。
现在我们需要考虑这么一种场景:我的任务需要长时间运行,并且我作为用户,我希望知道我的运行进度。
因此我们改进调度 HTTP 任务的方式,为此我们有一个假定,即用户提供的 HTTP 任务接口,是符合我们预期的。
因此,对于一个 HTTP 任务来说:
一些设计要点:
The text was updated successfully, but these errors were encountered: