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

Show last cron messages on monitor page #19223

Merged
merged 9 commits into from
Mar 29, 2022
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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: <strong>%s</strong>?
Expand Down
36 changes: 26 additions & 10 deletions services/cron/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
Expand Down
19 changes: 9 additions & 10 deletions services/cron/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ package cron
import (
"time"

user_model "code.gitea.io/gitea/models/user"

"github.com/unknwon/i18n"
)

Expand All @@ -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
}

Expand Down Expand Up @@ -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 {
zeripath marked this conversation as resolved.
Show resolved Hide resolved
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...)
zeripath marked this conversation as resolved.
Show resolved Hide resolved
}
50 changes: 37 additions & 13 deletions services/cron/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
}
Expand Down
35 changes: 35 additions & 0 deletions templates/admin/cron.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<h4 class="ui top attached header">
{{.i18n.Tr "admin.monitor.cron"}}
</h4>
<div class="ui attached table segment">
<form method="post" action="{{AppSubUrl}}/admin">
<table class="ui very basic striped table">
<thead>
<tr>
<th></th>
<th>{{.i18n.Tr "admin.monitor.name"}}</th>
<th>{{.i18n.Tr "admin.monitor.schedule"}}</th>
<th>{{.i18n.Tr "admin.monitor.next"}}</th>
<th>{{.i18n.Tr "admin.monitor.previous"}}</th>
<th>{{.i18n.Tr "admin.monitor.execute_times"}}</th>
<th>{{.i18n.Tr "admin.monitor.last_execution_result"}}</th>
</tr>
</thead>
<tbody>
{{range .Entries}}
<tr>
<td><button type="submit" class="ui green button" name="op" value="{{.Name}}" title="{{$.i18n.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td>
<td>{{$.i18n.Tr (printf "admin.dashboard.%s" .Name)}}</td>
<td>{{.Spec}}</td>
<td>{{DateFmtLong .Next}}</td>
<td>{{if gt .Prev.Year 1 }}{{DateFmtLong .Prev}}{{else}}N/A{{end}}</td>
<td>{{.ExecTimes}}</td>
<td {{if ne .Status ""}}class="tooltip" data-content="{{.FormatLastMessage $.i18n.Language}}"{{end}} >{{if eq .Status "" }}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}}</td>
</tr>
{{end}}
</tbody>
</table>
<input type="hidden" name="from" value="monitor"/>
{{.CsrfTokenHtml}}
</form>
</div>
35 changes: 1 addition & 34 deletions templates/admin/monitor.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,7 @@
{{template "admin/navbar" .}}
<div class="ui container">
{{template "base/alert" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "admin.monitor.cron"}}
</h4>
<div class="ui attached table segment">
<form method="post" action="{{AppSubUrl}}/admin">
<table class="ui very basic striped table">
<thead>
<tr>
<th></th>
<th>{{.i18n.Tr "admin.monitor.name"}}</th>
<th>{{.i18n.Tr "admin.monitor.schedule"}}</th>
<th>{{.i18n.Tr "admin.monitor.next"}}</th>
<th>{{.i18n.Tr "admin.monitor.previous"}}</th>
<th>{{.i18n.Tr "admin.monitor.execute_times"}}</th>
</tr>
</thead>
<tbody>
{{range .Entries}}
<tr>
<td><button type="submit" class="ui green button" name="op" value="{{.Name}}" title="{{$.i18n.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td>
<td>{{$.i18n.Tr (printf "admin.dashboard.%s" .Name)}}</td>
<td>{{.Spec}}</td>
<td>{{DateFmtLong .Next}}</td>
<td>{{if gt .Prev.Year 1 }}{{DateFmtLong .Prev}}{{else}}N/A{{end}}</td>
<td>{{.ExecTimes}}</td>
</tr>
{{end}}
</tbody>
</table>
<input type="hidden" name="from" value="monitor"/>
{{.CsrfTokenHtml}}
</form>
</div>

{{template "admin/cron" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "admin.monitor.queues"}}
</h4>
Expand Down