mirror of
https://github.com/hanzoai/base.git
synced 2026-10-21 03:41:50 +00:00
tools/cron is now a thin alias over tools/tasks. The legacy ticker + crontab-matching implementation is deleted; the public surface (New, Add/MustAdd, Remove, RemoveAll, Jobs, HasJob, Total, Start, Stop, SetInterval, SetTimezone, HasStarted) is preserved so no callsite changes. app.Cron() and app.Tasks() share a single *tasks.Client, giving one obvious way to schedule work. - tools/tasks/client.go gains the primitives the cron shim needs (Remove, RemoveAll, HasJob, Total, Schedules, Run, PauseAll, ResumeAll, ActiveTickerCount) plus a richer internal scheduleEntry so remote vs local ticking are distinguishable. - cron.Cron.Stop() now pauses local tickers while preserving the registry, matching the legacy semantics expected by ResetBootstrapState and the admin API. - core/base.go builds app.cron via cron.NewFromTasks(app.tasks) so both accessors feed the same state. - apis/cron.go keeps the /crons list + run-now behaviour; lookup now uses HasJob() for an O(1) precheck. Tests rewritten around the shim (TestCronDelegatesToTasks, TestCronAppFacadeLocal, TestCronAppFacadeRemoteFallback, TestCronNewFromTasksShared). Legacy 1-minute-tick assertions (TestCronStartStop) are SKIPped with a pointer to their replacement; crontab parser tests (tools/cron/schedule_test.go) still pass — the parser stays as a validation primitive for settings_model.go. docs/cron-to-tasks.md covers the migration path for services.
61 lines
1.3 KiB
Go
61 lines
1.3 KiB
Go
package apis
|
|
|
|
import (
|
|
"net/http"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/hanzoai/base/core"
|
|
"github.com/hanzoai/base/tools/cron"
|
|
"github.com/hanzoai/base/tools/router"
|
|
"github.com/hanzoai/base/tools/routine"
|
|
)
|
|
|
|
// bindCronApi registers the crons api endpoint.
|
|
func bindCronApi(app core.App, rg *router.RouterGroup[*core.RequestEvent]) {
|
|
subGroup := rg.Group("/crons").Bind(RequireSuperuserAuth())
|
|
subGroup.GET("", cronsList)
|
|
subGroup.POST("/{id}", cronRun)
|
|
}
|
|
|
|
func cronsList(e *core.RequestEvent) error {
|
|
jobs := e.App.Cron().Jobs()
|
|
|
|
slices.SortStableFunc(jobs, func(a, b *cron.Job) int {
|
|
if strings.HasPrefix(a.Id(), "__hz") {
|
|
return 1
|
|
}
|
|
if strings.HasPrefix(b.Id(), "__hz") {
|
|
return -1
|
|
}
|
|
return strings.Compare(a.Id(), b.Id())
|
|
})
|
|
|
|
return e.JSON(http.StatusOK, jobs)
|
|
}
|
|
|
|
func cronRun(e *core.RequestEvent) error {
|
|
cronId := e.Request.PathValue("id")
|
|
|
|
if !e.App.Cron().HasJob(cronId) {
|
|
return e.NotFoundError("Missing or invalid cron job", nil)
|
|
}
|
|
|
|
var foundJob *cron.Job
|
|
for _, j := range e.App.Cron().Jobs() {
|
|
if j.Id() == cronId {
|
|
foundJob = j
|
|
break
|
|
}
|
|
}
|
|
if foundJob == nil {
|
|
return e.NotFoundError("Missing or invalid cron job", nil)
|
|
}
|
|
|
|
routine.FireAndForget(func() {
|
|
foundJob.Run()
|
|
})
|
|
|
|
return e.NoContent(http.StatusNoContent)
|
|
}
|