Skip to content

Commit e3c3b33

Browse files
authored
Graceful: Xorm, RepoIndexer, Cron and Others (#9282)
* Change graceful to use a singleton obtained through GetManager instead of a global. * Graceful: Make TestPullRequests shutdownable * Graceful: Make the cron tasks graceful * Graceful: AddTestPullRequest run in graceful ctx * Graceful: SyncMirrors shutdown * Graceful: SetDefaultContext for Xorm to be HammerContext * Avoid starting graceful for migrate commands and checkout * Graceful: DeliverHooks now can be shutdown * Fix multiple syncing errors in modules/sync/UniqueQueue & Make UniqueQueue closable * Begin the process of making the repo indexer shutdown gracefully
1 parent 8bea92c commit e3c3b33

37 files changed

+631
-290
lines changed

cmd/migrate.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package cmd
66

77
import (
8+
"context"
9+
810
"code.gitea.io/gitea/models"
911
"code.gitea.io/gitea/models/migrations"
1012
"code.gitea.io/gitea/modules/log"
@@ -32,7 +34,7 @@ func runMigrate(ctx *cli.Context) error {
3234
log.Trace("Log path: %s", setting.LogRootPath)
3335
setting.InitDBConfig()
3436

35-
if err := models.NewEngine(migrations.Migrate); err != nil {
37+
if err := models.NewEngine(context.Background(), migrations.Migrate); err != nil {
3638
log.Fatal("Failed to initialize ORM engine: %v", err)
3739
return err
3840
}

cmd/web.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package cmd
66

77
import (
8+
"context"
89
"fmt"
910
"net/http"
1011
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
@@ -96,6 +97,10 @@ func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
9697
}
9798

9899
func runWeb(ctx *cli.Context) error {
100+
managerCtx, cancel := context.WithCancel(context.Background())
101+
graceful.InitManager(managerCtx)
102+
defer cancel()
103+
99104
if os.Getppid() > 1 && len(os.Getenv("LISTEN_FDS")) > 0 {
100105
log.Info("Restarting Gitea on PID: %d from parent PID: %d", os.Getpid(), os.Getppid())
101106
} else {
@@ -108,7 +113,7 @@ func runWeb(ctx *cli.Context) error {
108113
}
109114

110115
// Perform global initialization
111-
routers.GlobalInit()
116+
routers.GlobalInit(graceful.GetManager().HammerContext())
112117

113118
// Set up Macaron
114119
m := routes.NewMacaron()
@@ -199,8 +204,7 @@ func runWeb(ctx *cli.Context) error {
199204
log.Critical("Failed to start server: %v", err)
200205
}
201206
log.Info("HTTP Listener: %s Closed", listenAddr)
202-
graceful.Manager.WaitForServers()
203-
graceful.Manager.WaitForTerminate()
207+
<-graceful.GetManager().Done()
204208
log.Info("PID: %d Gitea Web Finished", os.Getpid())
205209
log.Close()
206210
return nil

cmd/web_graceful.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ func runHTTPSWithTLSConfig(network, listenAddr string, tlsConfig *tls.Config, m
2828

2929
// NoHTTPRedirector tells our cleanup routine that we will not be using a fallback http redirector
3030
func NoHTTPRedirector() {
31-
graceful.Manager.InformCleanup()
31+
graceful.GetManager().InformCleanup()
3232
}
3333

3434
// NoMainListener tells our cleanup routine that we will not be using a possibly provided listener
3535
// for our main HTTP/HTTPS service
3636
func NoMainListener() {
37-
graceful.Manager.InformCleanup()
37+
graceful.GetManager().InformCleanup()
3838
}
3939

4040
func runFCGI(network, listenAddr string, m http.Handler) error {

contrib/pr/checkout.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Checkout a PR and load the tests data into sqlite database
55
*/
66

77
import (
8+
"context"
89
"flag"
910
"fmt"
1011
"io/ioutil"
@@ -92,7 +93,7 @@ func runPR() {
9293
//x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
9394

9495
var helper testfixtures.Helper = &testfixtures.SQLite{}
95-
models.NewEngine(func(_ *xorm.Engine) error {
96+
models.NewEngine(context.Background(), func(_ *xorm.Engine) error {
9697
return nil
9798
})
9899
models.HasEngine = true

integrations/auth_ldap_test.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package integrations
66

77
import (
8+
"context"
89
"net/http"
910
"os"
1011
"strings"
@@ -147,7 +148,7 @@ func TestLDAPUserSync(t *testing.T) {
147148
}
148149
defer prepareTestEnv(t)()
149150
addAuthSourceLDAP(t, "")
150-
models.SyncExternalUsers()
151+
models.SyncExternalUsers(context.Background())
151152

152153
session := loginUser(t, "user1")
153154
// Check if users exists
@@ -206,7 +207,8 @@ func TestLDAPUserSSHKeySync(t *testing.T) {
206207
}
207208
defer prepareTestEnv(t)()
208209
addAuthSourceLDAP(t, "sshPublicKey")
209-
models.SyncExternalUsers()
210+
211+
models.SyncExternalUsers(context.Background())
210212

211213
// Check if users has SSH keys synced
212214
for _, u := range gitLDAPUsers {

integrations/integration_test.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package integrations
66

77
import (
88
"bytes"
9+
"context"
910
"database/sql"
1011
"encoding/json"
1112
"fmt"
@@ -24,6 +25,7 @@ import (
2425

2526
"code.gitea.io/gitea/models"
2627
"code.gitea.io/gitea/modules/base"
28+
"code.gitea.io/gitea/modules/graceful"
2729
"code.gitea.io/gitea/modules/setting"
2830
"code.gitea.io/gitea/routers"
2931
"code.gitea.io/gitea/routers/routes"
@@ -55,6 +57,10 @@ func NewNilResponseRecorder() *NilResponseRecorder {
5557
}
5658

5759
func TestMain(m *testing.M) {
60+
managerCtx, cancel := context.WithCancel(context.Background())
61+
graceful.InitManager(managerCtx)
62+
defer cancel()
63+
5864
initIntegrationTest()
5965
mac = routes.NewMacaron()
6066
routes.RegisterRoutes(mac)
@@ -171,7 +177,7 @@ func initIntegrationTest() {
171177
}
172178
defer db.Close()
173179
}
174-
routers.GlobalInit()
180+
routers.GlobalInit(graceful.GetManager().HammerContext())
175181
}
176182

177183
func prepareTestEnv(t testing.TB, skip ...int) func() {

integrations/migration-test/migration_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package migrations
66

77
import (
88
"compress/gzip"
9+
"context"
910
"database/sql"
1011
"fmt"
1112
"io/ioutil"
@@ -220,7 +221,7 @@ func doMigrationTest(t *testing.T, version string) {
220221
err := models.SetEngine()
221222
assert.NoError(t, err)
222223

223-
err = models.NewEngine(wrappedMigrate)
224+
err = models.NewEngine(context.Background(), wrappedMigrate)
224225
assert.NoError(t, err)
225226
currentEngine.Close()
226227
}

models/branches.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package models
66

77
import (
8+
"context"
89
"fmt"
910
"time"
1011

@@ -525,7 +526,8 @@ func (deletedBranch *DeletedBranch) LoadUser() {
525526
}
526527

527528
// RemoveOldDeletedBranches removes old deleted branches
528-
func RemoveOldDeletedBranches() {
529+
func RemoveOldDeletedBranches(ctx context.Context) {
530+
// Nothing to do for shutdown or terminate
529531
log.Trace("Doing: DeletedBranchesCleanup")
530532

531533
deleteBefore := time.Now().Add(-setting.Cron.DeletedBranchesCleanup.OlderThan)

models/models.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package models
77

88
import (
9+
"context"
910
"database/sql"
1011
"errors"
1112
"fmt"
@@ -164,11 +165,13 @@ func SetEngine() (err error) {
164165
}
165166

166167
// NewEngine initializes a new xorm.Engine
167-
func NewEngine(migrateFunc func(*xorm.Engine) error) (err error) {
168+
func NewEngine(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) {
168169
if err = SetEngine(); err != nil {
169170
return err
170171
}
171172

173+
x.SetDefaultContext(ctx)
174+
172175
if err = x.Ping(); err != nil {
173176
return err
174177
}

models/pull_list.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,12 @@ func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequ
6868
Find(&prs)
6969
}
7070

71-
// GetPullRequestsByCheckStatus returns all pull requests according the special checking status.
72-
func GetPullRequestsByCheckStatus(status PullRequestStatus) ([]*PullRequest, error) {
73-
prs := make([]*PullRequest, 0, 10)
74-
return prs, x.
71+
// GetPullRequestIDsByCheckStatus returns all pull requests according the special checking status.
72+
func GetPullRequestIDsByCheckStatus(status PullRequestStatus) ([]int64, error) {
73+
prs := make([]int64, 0, 10)
74+
return prs, x.Table("pull_request").
7575
Where("status=?", status).
76+
Cols("pull_request.id").
7677
Find(&prs)
7778
}
7879

models/repo.go

+56-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package models
77

88
import (
99
"bytes"
10+
"context"
1011
"crypto/md5"
1112
"errors"
1213
"fmt"
@@ -2098,19 +2099,27 @@ func DeleteRepositoryArchives() error {
20982099
}
20992100

21002101
// DeleteOldRepositoryArchives deletes old repository archives.
2101-
func DeleteOldRepositoryArchives() {
2102+
func DeleteOldRepositoryArchives(ctx context.Context) {
21022103
log.Trace("Doing: ArchiveCleanup")
21032104

2104-
if err := x.Where("id > 0").Iterate(new(Repository), deleteOldRepositoryArchives); err != nil {
2105+
if err := x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error {
2106+
return deleteOldRepositoryArchives(ctx, idx, bean)
2107+
}); err != nil {
21052108
log.Error("ArchiveClean: %v", err)
21062109
}
21072110
}
21082111

2109-
func deleteOldRepositoryArchives(idx int, bean interface{}) error {
2112+
func deleteOldRepositoryArchives(ctx context.Context, idx int, bean interface{}) error {
21102113
repo := bean.(*Repository)
21112114
basePath := filepath.Join(repo.RepoPath(), "archives")
21122115

21132116
for _, ty := range []string{"zip", "targz"} {
2117+
select {
2118+
case <-ctx.Done():
2119+
return fmt.Errorf("Aborted due to shutdown:\nin delete of old repository archives %v\nat delete file %s", repo, ty)
2120+
default:
2121+
}
2122+
21142123
path := filepath.Join(basePath, ty)
21152124
file, err := os.Open(path)
21162125
if err != nil {
@@ -2133,6 +2142,11 @@ func deleteOldRepositoryArchives(idx int, bean interface{}) error {
21332142
minimumOldestTime := time.Now().Add(-setting.Cron.ArchiveCleanup.OlderThan)
21342143
for _, info := range files {
21352144
if info.ModTime().Before(minimumOldestTime) && !info.IsDir() {
2145+
select {
2146+
case <-ctx.Done():
2147+
return fmt.Errorf("Aborted due to shutdown:\nin delete of old repository archives %v\nat delete file %s - %s", repo, ty, info.Name())
2148+
default:
2149+
}
21362150
toDelete := filepath.Join(path, info.Name())
21372151
// This is a best-effort purge, so we do not check error codes to confirm removal.
21382152
if err = os.Remove(toDelete); err != nil {
@@ -2226,13 +2240,17 @@ func SyncRepositoryHooks() error {
22262240
}
22272241

22282242
// GitFsck calls 'git fsck' to check repository health.
2229-
func GitFsck() {
2243+
func GitFsck(ctx context.Context) {
22302244
log.Trace("Doing: GitFsck")
2231-
22322245
if err := x.
22332246
Where("id>0 AND is_fsck_enabled=?", true).BufferSize(setting.Database.IterateBufferSize).
22342247
Iterate(new(Repository),
22352248
func(idx int, bean interface{}) error {
2249+
select {
2250+
case <-ctx.Done():
2251+
return fmt.Errorf("Aborted due to shutdown")
2252+
default:
2253+
}
22362254
repo := bean.(*Repository)
22372255
repoPath := repo.RepoPath()
22382256
log.Trace("Running health check on repository %s", repoPath)
@@ -2278,13 +2296,19 @@ type repoChecker struct {
22782296
desc string
22792297
}
22802298

2281-
func repoStatsCheck(checker *repoChecker) {
2299+
func repoStatsCheck(ctx context.Context, checker *repoChecker) {
22822300
results, err := x.Query(checker.querySQL)
22832301
if err != nil {
22842302
log.Error("Select %s: %v", checker.desc, err)
22852303
return
22862304
}
22872305
for _, result := range results {
2306+
select {
2307+
case <-ctx.Done():
2308+
log.Warn("CheckRepoStats: Aborting due to shutdown")
2309+
return
2310+
default:
2311+
}
22882312
id := com.StrTo(result["id"]).MustInt64()
22892313
log.Trace("Updating %s: %d", checker.desc, id)
22902314
_, err = x.Exec(checker.correctSQL, id, id)
@@ -2295,7 +2319,7 @@ func repoStatsCheck(checker *repoChecker) {
22952319
}
22962320

22972321
// CheckRepoStats checks the repository stats
2298-
func CheckRepoStats() {
2322+
func CheckRepoStats(ctx context.Context) {
22992323
log.Trace("Doing: CheckRepoStats")
23002324

23012325
checkers := []*repoChecker{
@@ -2331,7 +2355,13 @@ func CheckRepoStats() {
23312355
},
23322356
}
23332357
for i := range checkers {
2334-
repoStatsCheck(checkers[i])
2358+
select {
2359+
case <-ctx.Done():
2360+
log.Warn("CheckRepoStats: Aborting due to shutdown")
2361+
return
2362+
default:
2363+
repoStatsCheck(ctx, checkers[i])
2364+
}
23352365
}
23362366

23372367
// ***** START: Repository.NumClosedIssues *****
@@ -2341,6 +2371,12 @@ func CheckRepoStats() {
23412371
log.Error("Select %s: %v", desc, err)
23422372
} else {
23432373
for _, result := range results {
2374+
select {
2375+
case <-ctx.Done():
2376+
log.Warn("CheckRepoStats: Aborting due to shutdown")
2377+
return
2378+
default:
2379+
}
23442380
id := com.StrTo(result["id"]).MustInt64()
23452381
log.Trace("Updating %s: %d", desc, id)
23462382
_, err = x.Exec("UPDATE `repository` SET num_closed_issues=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, false, id)
@@ -2358,6 +2394,12 @@ func CheckRepoStats() {
23582394
log.Error("Select %s: %v", desc, err)
23592395
} else {
23602396
for _, result := range results {
2397+
select {
2398+
case <-ctx.Done():
2399+
log.Warn("CheckRepoStats: Aborting due to shutdown")
2400+
return
2401+
default:
2402+
}
23612403
id := com.StrTo(result["id"]).MustInt64()
23622404
log.Trace("Updating %s: %d", desc, id)
23632405
_, err = x.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, true, id)
@@ -2375,6 +2417,12 @@ func CheckRepoStats() {
23752417
log.Error("Select repository count 'num_forks': %v", err)
23762418
} else {
23772419
for _, result := range results {
2420+
select {
2421+
case <-ctx.Done():
2422+
log.Warn("CheckRepoStats: Aborting due to shutdown")
2423+
return
2424+
default:
2425+
}
23782426
id := com.StrTo(result["id"]).MustInt64()
23792427
log.Trace("Updating repository count 'num_forks': %d", id)
23802428

0 commit comments

Comments
 (0)