loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

show manual cron run's last time (#27544)

- Currently in the cron tasks, the 'Previous Time' only displays the
previous time of when the cron library executes the function, but not
any of the manual executions of the task.
- Store the last run's time in memory in the Task struct and use that,
when that time is later than time that the cron library has executed
this task.
- This ensures that if an instance admin manually starts a task, there's
feedback that this task is/has been run, because the task might be run
that quick, that the status icon already has been changed to an
checkmark,
- Tasks that are executed at startup now reflect this as well, as the
time of the execution of that task on startup is now being shown as
'Previous Time'.
- Added integration tests for the API part, which is easier to test
because querying the HTML table of cron tasks is non-trivial.
- Resolves https://codeberg.org/forgejo/forgejo/issues/949

(cherry picked from commit fd34fdac1408ece6b7d9fe6a76501ed9a45d06fa)

---------

Co-authored-by: Gusted <postmaster@gusted.xyz>
Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
Co-authored-by: silverwind <me@silverwind.io>

authored by

Earl Warren
Gusted
KN4CK3R
silverwind
and committed by
GitHub
1050d7a7 dc7cf7a9

+65
+6
services/cron/cron.go
··· 106 106 next = e.NextRun() 107 107 prev = e.PreviousRun() 108 108 } 109 + 110 + // If the manual run is after the cron run, use that instead. 111 + if prev.Before(task.LastRun) { 112 + prev = task.LastRun 113 + } 114 + 109 115 task.lock.Lock() 110 116 tTable = append(tTable, &TaskTableRow{ 111 117 Name: task.Name,
+9
services/cron/tasks.go
··· 9 9 "reflect" 10 10 "strings" 11 11 "sync" 12 + "time" 12 13 13 14 "code.gitea.io/gitea/models/db" 14 15 system_model "code.gitea.io/gitea/models/system" ··· 37 38 LastMessage string 38 39 LastDoer string 39 40 ExecTimes int64 41 + // This stores the time of the last manual run of this task. 42 + LastRun time.Time 40 43 } 41 44 42 45 // DoRunAtStart returns if this task should run at the start ··· 88 91 } 89 92 }() 90 93 graceful.GetManager().RunWithShutdownContext(func(baseCtx context.Context) { 94 + // Store the time of this run, before the function is executed, so it 95 + // matches the behavior of what the cron library does. 96 + t.lock.Lock() 97 + t.LastRun = time.Now() 98 + t.lock.Unlock() 99 + 91 100 pm := process.GetManager() 92 101 doerName := "" 93 102 if doer != nil && doer.ID != -1 {
+50
tests/integration/api_admin_test.go
··· 7 7 "fmt" 8 8 "net/http" 9 9 "testing" 10 + "time" 10 11 11 12 asymkey_model "code.gitea.io/gitea/models/asymkey" 12 13 auth_model "code.gitea.io/gitea/models/auth" ··· 282 283 }) 283 284 MakeRequest(t, req, http.StatusOK) 284 285 } 286 + 287 + func TestAPICron(t *testing.T) { 288 + defer tests.PrepareTestEnv(t)() 289 + 290 + // user1 is an admin user 291 + session := loginUser(t, "user1") 292 + 293 + t.Run("List", func(t *testing.T) { 294 + defer tests.PrintCurrentTest(t)() 295 + 296 + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin) 297 + urlStr := fmt.Sprintf("/api/v1/admin/cron?token=%s", token) 298 + req := NewRequest(t, "GET", urlStr) 299 + resp := MakeRequest(t, req, http.StatusOK) 300 + 301 + assert.Equal(t, "28", resp.Header().Get("X-Total-Count")) 302 + 303 + var crons []api.Cron 304 + DecodeJSON(t, resp, &crons) 305 + assert.Len(t, crons, 28) 306 + }) 307 + 308 + t.Run("Execute", func(t *testing.T) { 309 + defer tests.PrintCurrentTest(t)() 310 + 311 + now := time.Now() 312 + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) 313 + // Archive cleanup is harmless, because in the test environment there are none 314 + // and is thus an NOOP operation and therefore doesn't interfere with any other 315 + // tests. 316 + urlStr := fmt.Sprintf("/api/v1/admin/cron/archive_cleanup?token=%s", token) 317 + req := NewRequest(t, "POST", urlStr) 318 + MakeRequest(t, req, http.StatusNoContent) 319 + 320 + // Check for the latest run time for this cron, to ensure it has been run. 321 + urlStr = fmt.Sprintf("/api/v1/admin/cron?token=%s", token) 322 + req = NewRequest(t, "GET", urlStr) 323 + resp := MakeRequest(t, req, http.StatusOK) 324 + 325 + var crons []api.Cron 326 + DecodeJSON(t, resp, &crons) 327 + 328 + for _, cron := range crons { 329 + if cron.Name == "archive_cleanup" { 330 + assert.True(t, now.Before(cron.Prev)) 331 + } 332 + } 333 + }) 334 + }