From 90e0a402c1185827fd3d5352ca915c531ce1e7b1 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 29 Mar 2022 02:31:07 +0100 Subject: [PATCH] Show last cron messages on monitor page (#19223) As discussed on #19221 we should store the results of the last task message on the crontask and show them on the monitor page. Signed-off-by: Andrew Thornton Co-authored-by: wxiaoguang --- options/locale/locale_en-US.ini | 1 + services/cron/cron.go | 36 +++++++++++++++++------- services/cron/setting.go | 19 ++++++------- services/cron/tasks.go | 50 ++++++++++++++++++++++++--------- templates/admin/cron.tmpl | 35 +++++++++++++++++++++++ templates/admin/monitor.tmpl | 35 +---------------------- 6 files changed, 109 insertions(+), 67 deletions(-) create mode 100644 templates/admin/cron.tmpl diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 5008cd2bab4..0a4abde4082 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2816,6 +2816,7 @@ monitor.process = Running Processes monitor.desc = Description monitor.start = Start Time monitor.execute_time = Execution Time +monitor.last_execution_result = Result monitor.process.cancel = Cancel process monitor.process.cancel_desc = Cancelling a process may cause data loss monitor.process.cancel_notices = Cancel: %s? diff --git a/services/cron/cron.go b/services/cron/cron.go index 19f703caf18..9fe90d42308 100644 --- a/services/cron/cron.go +++ b/services/cron/cron.go @@ -47,11 +47,23 @@ func NewContext() { // TaskTableRow represents a task row in the tasks table type TaskTableRow struct { - Name string - Spec string - Next time.Time - Prev time.Time - ExecTimes int64 + Name string + Spec string + Next time.Time + Prev time.Time + Status string + LastMessage string + LastDoer string + ExecTimes int64 + task *Task +} + +func (t *TaskTableRow) FormatLastMessage(locale string) string { + if t.Status == "finished" { + return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer) + } + + return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer, t.LastMessage) } // TaskTable represents a table of tasks @@ -80,11 +92,15 @@ func ListTasks() TaskTable { } task.lock.Lock() tTable = append(tTable, &TaskTableRow{ - Name: task.Name, - Spec: spec, - Next: next, - Prev: prev, - ExecTimes: task.ExecTimes, + Name: task.Name, + Spec: spec, + Next: next, + Prev: prev, + ExecTimes: task.ExecTimes, + LastMessage: task.LastMessage, + Status: task.Status, + LastDoer: task.LastDoer, + task: task, }) task.lock.Unlock() } diff --git a/services/cron/setting.go b/services/cron/setting.go index 4ccb7c7ce3b..f0683393ff8 100644 --- a/services/cron/setting.go +++ b/services/cron/setting.go @@ -7,8 +7,6 @@ package cron import ( "time" - user_model "code.gitea.io/gitea/models/user" - "github.com/unknwon/i18n" ) @@ -17,7 +15,7 @@ type Config interface { IsEnabled() bool DoRunAtStart() bool GetSchedule() string - FormatMessage(name, status string, doer *user_model.User, args ...interface{}) string + FormatMessage(locale, name, status, doer string, args ...interface{}) string DoNoticeOnSuccess() bool } @@ -70,19 +68,20 @@ func (b *BaseConfig) DoNoticeOnSuccess() bool { } // FormatMessage returns a message for the task -func (b *BaseConfig) FormatMessage(name, status string, doer *user_model.User, args ...interface{}) string { +// Please note the `status` string will be concatenated with `admin.dashboard.cron.` and `admin.dashboard.task.` to provide locale messages. Similarly `name` will be composed with `admin.dashboard.` to provide the locale name for the task. +func (b *BaseConfig) FormatMessage(locale, name, status, doer string, args ...interface{}) string { realArgs := make([]interface{}, 0, len(args)+2) - realArgs = append(realArgs, i18n.Tr("en-US", "admin.dashboard."+name)) - if doer == nil { + realArgs = append(realArgs, i18n.Tr(locale, "admin.dashboard."+name)) + if doer == "" { realArgs = append(realArgs, "(Cron)") } else { - realArgs = append(realArgs, doer.Name) + realArgs = append(realArgs, doer) } if len(args) > 0 { realArgs = append(realArgs, args...) } - if doer == nil || (doer.ID == -1 && doer.Name == "(Cron)") { - return i18n.Tr("en-US", "admin.dashboard.cron."+status, realArgs...) + if doer == "" { + return i18n.Tr(locale, "admin.dashboard.cron."+status, realArgs...) } - return i18n.Tr("en-US", "admin.dashboard.task."+status, realArgs...) + return i18n.Tr(locale, "admin.dashboard.task."+status, realArgs...) } diff --git a/services/cron/tasks.go b/services/cron/tasks.go index 070fb6e9e16..2252ad21e25 100644 --- a/services/cron/tasks.go +++ b/services/cron/tasks.go @@ -29,11 +29,14 @@ var ( // Task represents a Cron task type Task struct { - lock sync.Mutex - Name string - config Config - fun func(context.Context, *user_model.User, Config) error - ExecTimes int64 + lock sync.Mutex + Name string + config Config + fun func(context.Context, *user_model.User, Config) error + Status string + LastMessage string + LastDoer string + ExecTimes int64 } // DoRunAtStart returns if this task should run at the start @@ -86,24 +89,45 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) { }() graceful.GetManager().RunWithShutdownContext(func(baseCtx context.Context) { pm := process.GetManager() - ctx, _, finished := pm.AddContext(baseCtx, config.FormatMessage(t.Name, "process", doer)) + doerName := "" + if doer != nil && doer.ID != -1 { + doerName = doer.Name + } + + ctx, _, finished := pm.AddContext(baseCtx, config.FormatMessage("en-US", t.Name, "process", doerName)) defer finished() if err := t.fun(ctx, doer, config); err != nil { + var message string + var status string if db.IsErrCancelled(err) { - message := err.(db.ErrCancelled).Message - if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(t.Name, "aborted", doer, message)); err != nil { - log.Error("CreateNotice: %v", err) - } - return + status = "cancelled" + message = err.(db.ErrCancelled).Message + } else { + status = "error" + message = err.Error() } - if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(t.Name, "error", doer, err)); err != nil { + + t.lock.Lock() + t.LastMessage = message + t.Status = status + t.LastDoer = doerName + t.lock.Unlock() + + if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage("en-US", t.Name, "cancelled", doerName, message)); err != nil { log.Error("CreateNotice: %v", err) } return } + + t.lock.Lock() + t.Status = "finished" + t.LastMessage = "" + t.LastDoer = doerName + t.lock.Unlock() + if config.DoNoticeOnSuccess() { - if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(t.Name, "finished", doer)); err != nil { + if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage("en-US", t.Name, "finished", doerName)); err != nil { log.Error("CreateNotice: %v", err) } } diff --git a/templates/admin/cron.tmpl b/templates/admin/cron.tmpl new file mode 100644 index 00000000000..30277177ed0 --- /dev/null +++ b/templates/admin/cron.tmpl @@ -0,0 +1,35 @@ +

+ {{.i18n.Tr "admin.monitor.cron"}} +

+
+
+ + + + + + + + + + + + + + {{range .Entries}} + + + + + + + + + + {{end}} + +
{{.i18n.Tr "admin.monitor.name"}}{{.i18n.Tr "admin.monitor.schedule"}}{{.i18n.Tr "admin.monitor.next"}}{{.i18n.Tr "admin.monitor.previous"}}{{.i18n.Tr "admin.monitor.execute_times"}}{{.i18n.Tr "admin.monitor.last_execution_result"}}
{{$.i18n.Tr (printf "admin.dashboard.%s" .Name)}}{{.Spec}}{{DateFmtLong .Next}}{{if gt .Prev.Year 1 }}{{DateFmtLong .Prev}}{{else}}N/A{{end}}{{.ExecTimes}}{{if eq .Status "" }}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}}
+ + {{.CsrfTokenHtml}} +
+
diff --git a/templates/admin/monitor.tmpl b/templates/admin/monitor.tmpl index a35b587bd50..443159f8cea 100644 --- a/templates/admin/monitor.tmpl +++ b/templates/admin/monitor.tmpl @@ -3,40 +3,7 @@ {{template "admin/navbar" .}}
{{template "base/alert" .}} -

- {{.i18n.Tr "admin.monitor.cron"}} -

-
-
- - - - - - - - - - - - - {{range .Entries}} - - - - - - - - - {{end}} - -
{{.i18n.Tr "admin.monitor.name"}}{{.i18n.Tr "admin.monitor.schedule"}}{{.i18n.Tr "admin.monitor.next"}}{{.i18n.Tr "admin.monitor.previous"}}{{.i18n.Tr "admin.monitor.execute_times"}}
{{$.i18n.Tr (printf "admin.dashboard.%s" .Name)}}{{.Spec}}{{DateFmtLong .Next}}{{if gt .Prev.Year 1 }}{{DateFmtLong .Prev}}{{else}}N/A{{end}}{{.ExecTimes}}
- - {{.CsrfTokenHtml}} -
-
- + {{template "admin/cron" .}}

{{.i18n.Tr "admin.monitor.queues"}}