Replace gogs/cron with go-co-op/gocron (#25977)
Replace `github.com/gogs/cron` with `github.com/go-co-op/gocron` as the former package is not maintained for many years. --------- Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
parent
f3d41c61eb
commit
f2138d6968
6 changed files with 123 additions and 22 deletions
|
@ -14,10 +14,10 @@ import (
|
|||
"code.gitea.io/gitea/modules/sync"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/gogs/cron"
|
||||
"github.com/go-co-op/gocron"
|
||||
)
|
||||
|
||||
var c = cron.New()
|
||||
var scheduler = gocron.NewScheduler(time.Local)
|
||||
|
||||
// Prevent duplicate running tasks.
|
||||
var taskStatusTable = sync.NewStatusTable()
|
||||
|
@ -39,11 +39,11 @@ func NewContext(original context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
c.Start()
|
||||
scheduler.StartAsync()
|
||||
started = true
|
||||
lock.Unlock()
|
||||
graceful.GetManager().RunAtShutdown(context.Background(), func() {
|
||||
c.Stop()
|
||||
scheduler.Stop()
|
||||
lock.Lock()
|
||||
started = false
|
||||
lock.Unlock()
|
||||
|
@ -77,13 +77,20 @@ type TaskTable []*TaskTableRow
|
|||
|
||||
// ListTasks returns all running cron tasks.
|
||||
func ListTasks() TaskTable {
|
||||
entries := c.Entries()
|
||||
eMap := map[string]*cron.Entry{}
|
||||
for _, e := range entries {
|
||||
eMap[e.Description] = e
|
||||
jobs := scheduler.Jobs()
|
||||
jobMap := map[string]*gocron.Job{}
|
||||
for _, job := range jobs {
|
||||
// the first tag is the task name
|
||||
tags := job.Tags()
|
||||
if len(tags) == 0 { // should never happen
|
||||
continue
|
||||
}
|
||||
jobMap[job.Tags()[0]] = job
|
||||
}
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
tTable := make([]*TaskTableRow, 0, len(tasks))
|
||||
for _, task := range tasks {
|
||||
spec := "-"
|
||||
|
@ -91,10 +98,13 @@ func ListTasks() TaskTable {
|
|||
next time.Time
|
||||
prev time.Time
|
||||
)
|
||||
if e, ok := eMap[task.Name]; ok {
|
||||
spec = e.Spec
|
||||
next = e.Next
|
||||
prev = e.Prev
|
||||
if e, ok := jobMap[task.Name]; ok {
|
||||
tags := e.Tags()
|
||||
if len(tags) > 1 {
|
||||
spec = tags[1] // the second tag is the task spec
|
||||
}
|
||||
next = e.NextRun()
|
||||
prev = e.PreviousRun()
|
||||
}
|
||||
task.lock.Lock()
|
||||
tTable = append(tTable, &TaskTableRow{
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
|
@ -176,8 +177,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo
|
|||
|
||||
if config.IsEnabled() {
|
||||
// We cannot use the entry return as there is no way to lock it
|
||||
if _, err = c.AddJob(name, config.GetSchedule(), task); err != nil {
|
||||
log.Error("Unable to register cron task with name: %s Error: %v", name, err)
|
||||
if err := addTaskToScheduler(task); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -199,3 +199,21 @@ func RegisterTaskFatal(name string, config Config, fun func(context.Context, *us
|
|||
log.Fatal("Unable to register cron task %s Error: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func addTaskToScheduler(task *Task) error {
|
||||
tags := []string{task.Name, task.config.GetSchedule()} // name and schedule can't be get from job, so we add them as tag
|
||||
if scheduleHasSeconds(task.config.GetSchedule()) {
|
||||
scheduler = scheduler.CronWithSeconds(task.config.GetSchedule())
|
||||
} else {
|
||||
scheduler = scheduler.Cron(task.config.GetSchedule())
|
||||
}
|
||||
if _, err := scheduler.Tag(tags...).Do(task.Run); err != nil {
|
||||
log.Error("Unable to register cron task with name: %s Error: %v", task.Name, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func scheduleHasSeconds(schedule string) bool {
|
||||
return len(strings.Fields(schedule)) >= 6
|
||||
}
|
||||
|
|
61
services/cron/tasks_test.go
Normal file
61
services/cron/tasks_test.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cron
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAddTaskToScheduler(t *testing.T) {
|
||||
assert.Len(t, scheduler.Jobs(), 0)
|
||||
defer scheduler.Clear()
|
||||
|
||||
// no seconds
|
||||
err := addTaskToScheduler(&Task{
|
||||
Name: "task 1",
|
||||
config: &BaseConfig{
|
||||
Schedule: "5 4 * * *",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, scheduler.Jobs(), 1)
|
||||
assert.Equal(t, "task 1", scheduler.Jobs()[0].Tags()[0])
|
||||
assert.Equal(t, "5 4 * * *", scheduler.Jobs()[0].Tags()[1])
|
||||
|
||||
// with seconds
|
||||
err = addTaskToScheduler(&Task{
|
||||
Name: "task 2",
|
||||
config: &BaseConfig{
|
||||
Schedule: "30 5 4 * * *",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, scheduler.Jobs(), 2)
|
||||
assert.Equal(t, "task 2", scheduler.Jobs()[1].Tags()[0])
|
||||
assert.Equal(t, "30 5 4 * * *", scheduler.Jobs()[1].Tags()[1])
|
||||
}
|
||||
|
||||
func TestScheduleHasSeconds(t *testing.T) {
|
||||
tests := []struct {
|
||||
schedule string
|
||||
hasSecond bool
|
||||
}{
|
||||
{"* * * * * *", true},
|
||||
{"* * * * *", false},
|
||||
{"5 4 * * *", false},
|
||||
{"5 4 * * *", false},
|
||||
{"5,8 4 * * *", false},
|
||||
{"* * * * * *", true},
|
||||
{"5,8 4 * * *", false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
assert.Equal(t, test.hasSecond, scheduleHasSeconds(test.schedule))
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue