code.gitea.io/gitea@v1.21.7/services/cron/cron.go (about)

     1  // Copyright 2014 The Gogs Authors. All rights reserved.
     2  // Copyright 2019 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package cron
     6  
     7  import (
     8  	"context"
     9  	"runtime/pprof"
    10  	"time"
    11  
    12  	"code.gitea.io/gitea/modules/graceful"
    13  	"code.gitea.io/gitea/modules/process"
    14  	"code.gitea.io/gitea/modules/sync"
    15  	"code.gitea.io/gitea/modules/translation"
    16  
    17  	"github.com/go-co-op/gocron"
    18  )
    19  
    20  var scheduler = gocron.NewScheduler(time.Local)
    21  
    22  // Prevent duplicate running tasks.
    23  var taskStatusTable = sync.NewStatusTable()
    24  
    25  // NewContext begins cron tasks
    26  // Each cron task is run within the shutdown context as a running server
    27  // AtShutdown the cron server is stopped
    28  func NewContext(original context.Context) {
    29  	defer pprof.SetGoroutineLabels(original)
    30  	_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().ShutdownContext(), "Service: Cron", process.SystemProcessType, true)
    31  	initBasicTasks()
    32  	initExtendedTasks()
    33  	initActionsTasks()
    34  
    35  	lock.Lock()
    36  	for _, task := range tasks {
    37  		if task.IsEnabled() && task.DoRunAtStart() {
    38  			go task.Run()
    39  		}
    40  	}
    41  
    42  	scheduler.StartAsync()
    43  	started = true
    44  	lock.Unlock()
    45  	graceful.GetManager().RunAtShutdown(context.Background(), func() {
    46  		scheduler.Stop()
    47  		lock.Lock()
    48  		started = false
    49  		lock.Unlock()
    50  		finished()
    51  	})
    52  }
    53  
    54  // TaskTableRow represents a task row in the tasks table
    55  type TaskTableRow struct {
    56  	Name        string
    57  	Spec        string
    58  	Next        time.Time
    59  	Prev        time.Time
    60  	Status      string
    61  	LastMessage string
    62  	LastDoer    string
    63  	ExecTimes   int64
    64  	task        *Task
    65  }
    66  
    67  func (t *TaskTableRow) FormatLastMessage(locale translation.Locale) string {
    68  	if t.Status == "finished" {
    69  		return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer)
    70  	}
    71  
    72  	return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer, t.LastMessage)
    73  }
    74  
    75  // TaskTable represents a table of tasks
    76  type TaskTable []*TaskTableRow
    77  
    78  // ListTasks returns all running cron tasks.
    79  func ListTasks() TaskTable {
    80  	jobs := scheduler.Jobs()
    81  	jobMap := map[string]*gocron.Job{}
    82  	for _, job := range jobs {
    83  		// the first tag is the task name
    84  		tags := job.Tags()
    85  		if len(tags) == 0 { // should never happen
    86  			continue
    87  		}
    88  		jobMap[job.Tags()[0]] = job
    89  	}
    90  
    91  	lock.Lock()
    92  	defer lock.Unlock()
    93  
    94  	tTable := make([]*TaskTableRow, 0, len(tasks))
    95  	for _, task := range tasks {
    96  		spec := "-"
    97  		var (
    98  			next time.Time
    99  			prev time.Time
   100  		)
   101  		if e, ok := jobMap[task.Name]; ok {
   102  			tags := e.Tags()
   103  			if len(tags) > 1 {
   104  				spec = tags[1] // the second tag is the task spec
   105  			}
   106  			next = e.NextRun()
   107  			prev = e.PreviousRun()
   108  		}
   109  
   110  		task.lock.Lock()
   111  		// If the manual run is after the cron run, use that instead.
   112  		if prev.Before(task.LastRun) {
   113  			prev = task.LastRun
   114  		}
   115  		tTable = append(tTable, &TaskTableRow{
   116  			Name:        task.Name,
   117  			Spec:        spec,
   118  			Next:        next,
   119  			Prev:        prev,
   120  			ExecTimes:   task.ExecTimes,
   121  			LastMessage: task.LastMessage,
   122  			Status:      task.Status,
   123  			LastDoer:    task.LastDoer,
   124  			task:        task,
   125  		})
   126  		task.lock.Unlock()
   127  	}
   128  
   129  	return tTable
   130  }