mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	@@ -204,12 +204,13 @@ func getIssueIndexerQueueHandler(ctx context.Context) func(items ...*IndexerMeta
 | 
				
			|||||||
func populateIssueIndexer(ctx context.Context) {
 | 
					func populateIssueIndexer(ctx context.Context) {
 | 
				
			||||||
	ctx, _, finished := process.GetManager().AddTypedContext(ctx, "Service: PopulateIssueIndexer", process.SystemProcessType, true)
 | 
						ctx, _, finished := process.GetManager().AddTypedContext(ctx, "Service: PopulateIssueIndexer", process.SystemProcessType, true)
 | 
				
			||||||
	defer finished()
 | 
						defer finished()
 | 
				
			||||||
	if err := PopulateIssueIndexer(ctx, true); err != nil {
 | 
						ctx = contextWithKeepRetry(ctx) // keep retrying since it's a background task
 | 
				
			||||||
 | 
						if err := PopulateIssueIndexer(ctx); err != nil {
 | 
				
			||||||
		log.Error("Issue indexer population failed: %v", err)
 | 
							log.Error("Issue indexer population failed: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func PopulateIssueIndexer(ctx context.Context, keepRetrying bool) error {
 | 
					func PopulateIssueIndexer(ctx context.Context) error {
 | 
				
			||||||
	for page := 1; ; page++ {
 | 
						for page := 1; ; page++ {
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case <-ctx.Done():
 | 
							case <-ctx.Done():
 | 
				
			||||||
@@ -232,20 +233,8 @@ func PopulateIssueIndexer(ctx context.Context, keepRetrying bool) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, repo := range repos {
 | 
							for _, repo := range repos {
 | 
				
			||||||
			for {
 | 
								if err := updateRepoIndexer(ctx, repo.ID); err != nil {
 | 
				
			||||||
				select {
 | 
									return fmt.Errorf("populate issue indexer for repo %d: %v", repo.ID, err)
 | 
				
			||||||
				case <-ctx.Done():
 | 
					 | 
				
			||||||
					return fmt.Errorf("shutdown before completion: %w", ctx.Err())
 | 
					 | 
				
			||||||
				default:
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if err := updateRepoIndexer(ctx, repo.ID); err != nil {
 | 
					 | 
				
			||||||
					if keepRetrying && ctx.Err() == nil {
 | 
					 | 
				
			||||||
						log.Warn("Retry to populate issue indexer for repo %d: %v", repo.ID, err)
 | 
					 | 
				
			||||||
						continue
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return fmt.Errorf("populate issue indexer for repo %d: %v", repo.ID, err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				break
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -259,8 +248,8 @@ func UpdateRepoIndexer(ctx context.Context, repoID int64) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateIssueIndexer add/update an issue to the issue indexer
 | 
					// UpdateIssueIndexer add/update an issue to the issue indexer
 | 
				
			||||||
func UpdateIssueIndexer(issueID int64) {
 | 
					func UpdateIssueIndexer(ctx context.Context, issueID int64) {
 | 
				
			||||||
	if err := updateIssueIndexer(issueID); err != nil {
 | 
						if err := updateIssueIndexer(ctx, issueID); err != nil {
 | 
				
			||||||
		log.Error("Unable to push issue %d to issue indexer: %v", issueID, err)
 | 
							log.Error("Unable to push issue %d to issue indexer: %v", issueID, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -127,15 +127,15 @@ func updateRepoIndexer(ctx context.Context, repoID int64) error {
 | 
				
			|||||||
		return fmt.Errorf("issue_model.GetIssueIDsByRepoID: %w", err)
 | 
							return fmt.Errorf("issue_model.GetIssueIDsByRepoID: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, id := range ids {
 | 
						for _, id := range ids {
 | 
				
			||||||
		if err := updateIssueIndexer(id); err != nil {
 | 
							if err := updateIssueIndexer(ctx, id); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func updateIssueIndexer(issueID int64) error {
 | 
					func updateIssueIndexer(ctx context.Context, issueID int64) error {
 | 
				
			||||||
	return pushIssueIndexerQueue(&IndexerMetadata{ID: issueID})
 | 
						return pushIssueIndexerQueue(ctx, &IndexerMetadata{ID: issueID})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func deleteRepoIssueIndexer(ctx context.Context, repoID int64) error {
 | 
					func deleteRepoIssueIndexer(ctx context.Context, repoID int64) error {
 | 
				
			||||||
@@ -148,13 +148,21 @@ func deleteRepoIssueIndexer(ctx context.Context, repoID int64) error {
 | 
				
			|||||||
	if len(ids) == 0 {
 | 
						if len(ids) == 0 {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return pushIssueIndexerQueue(&IndexerMetadata{
 | 
						return pushIssueIndexerQueue(ctx, &IndexerMetadata{
 | 
				
			||||||
		IDs:      ids,
 | 
							IDs:      ids,
 | 
				
			||||||
		IsDelete: true,
 | 
							IsDelete: true,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func pushIssueIndexerQueue(data *IndexerMetadata) error {
 | 
					type keepRetryKey struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// contextWithKeepRetry returns a context with a key indicating that the indexer should keep retrying.
 | 
				
			||||||
 | 
					// Please note that it's for background tasks only, and it should not be used for user requests, or it may cause blocking.
 | 
				
			||||||
 | 
					func contextWithKeepRetry(ctx context.Context) context.Context {
 | 
				
			||||||
 | 
						return context.WithValue(ctx, keepRetryKey{}, true)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func pushIssueIndexerQueue(ctx context.Context, data *IndexerMetadata) error {
 | 
				
			||||||
	if issueIndexerQueue == nil {
 | 
						if issueIndexerQueue == nil {
 | 
				
			||||||
		// Some unit tests will trigger indexing, but the queue is not initialized.
 | 
							// Some unit tests will trigger indexing, but the queue is not initialized.
 | 
				
			||||||
		// It's OK to ignore it, but log a warning message in case it's not a unit test.
 | 
							// It's OK to ignore it, but log a warning message in case it's not a unit test.
 | 
				
			||||||
@@ -162,12 +170,26 @@ func pushIssueIndexerQueue(data *IndexerMetadata) error {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := issueIndexerQueue.Push(data)
 | 
						for {
 | 
				
			||||||
	if errors.Is(err, queue.ErrAlreadyInQueue) {
 | 
							select {
 | 
				
			||||||
		return nil
 | 
							case <-ctx.Done():
 | 
				
			||||||
 | 
								return ctx.Err()
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err := issueIndexerQueue.Push(data)
 | 
				
			||||||
 | 
							if errors.Is(err, queue.ErrAlreadyInQueue) {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if errors.Is(err, context.DeadlineExceeded) { // the queue is full
 | 
				
			||||||
 | 
								log.Warn("It seems that issue indexer is slow and the queue is full. Please check the issue indexer or increase the queue size.")
 | 
				
			||||||
 | 
								if ctx.Value(keepRetryKey{}) == nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// It will be better to increase the queue size instead of retrying, but users may ignore the previous warning message.
 | 
				
			||||||
 | 
								// However, even it retries, it may still cause index loss when there's a deadline in the context.
 | 
				
			||||||
 | 
								log.Debug("Retry to push %+v to issue indexer queue", data)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if errors.Is(err, context.DeadlineExceeded) {
 | 
					 | 
				
			||||||
		log.Warn("It seems that issue indexer is slow and the queue is full. Please check the issue indexer or increase the queue size.")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -219,7 +219,7 @@ func registerRebuildIssueIndexer() {
 | 
				
			|||||||
		RunAtStart: false,
 | 
							RunAtStart: false,
 | 
				
			||||||
		Schedule:   "@annually",
 | 
							Schedule:   "@annually",
 | 
				
			||||||
	}, func(ctx context.Context, _ *user_model.User, config Config) error {
 | 
						}, func(ctx context.Context, _ *user_model.User, config Config) error {
 | 
				
			||||||
		return issue_indexer.PopulateIssueIndexer(ctx, false)
 | 
							return issue_indexer.PopulateIssueIndexer(ctx)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,11 +36,11 @@ func (r *indexerNotifier) AdoptRepository(ctx context.Context, doer, u *user_mod
 | 
				
			|||||||
func (r *indexerNotifier) CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository,
 | 
					func (r *indexerNotifier) CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository,
 | 
				
			||||||
	issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
 | 
						issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) NewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) {
 | 
					func (r *indexerNotifier) NewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) {
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) {
 | 
					func (r *indexerNotifier) NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) {
 | 
				
			||||||
@@ -48,7 +48,7 @@ func (r *indexerNotifier) NewPullRequest(ctx context.Context, pr *issues_model.P
 | 
				
			|||||||
		log.Error("LoadIssue: %v", err)
 | 
							log.Error("LoadIssue: %v", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(pr.Issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, pr.Issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) UpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) {
 | 
					func (r *indexerNotifier) UpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) {
 | 
				
			||||||
@@ -56,7 +56,7 @@ func (r *indexerNotifier) UpdateComment(ctx context.Context, doer *user_model.Us
 | 
				
			|||||||
		log.Error("LoadIssue: %v", err)
 | 
							log.Error("LoadIssue: %v", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(c.Issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, c.Issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) {
 | 
					func (r *indexerNotifier) DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) {
 | 
				
			||||||
@@ -64,7 +64,7 @@ func (r *indexerNotifier) DeleteComment(ctx context.Context, doer *user_model.Us
 | 
				
			|||||||
		log.Error("LoadIssue: %v", err)
 | 
							log.Error("LoadIssue: %v", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(comment.Issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, comment.Issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) {
 | 
					func (r *indexerNotifier) DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) {
 | 
				
			||||||
@@ -120,13 +120,13 @@ func (r *indexerNotifier) ChangeDefaultBranch(ctx context.Context, repo *repo_mo
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) IssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
 | 
					func (r *indexerNotifier) IssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) IssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
 | 
					func (r *indexerNotifier) IssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) IssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldRef string) {
 | 
					func (r *indexerNotifier) IssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldRef string) {
 | 
				
			||||||
	issue_indexer.UpdateIssueIndexer(issue.ID)
 | 
						issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
package integration
 | 
					package integration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
@@ -99,7 +100,7 @@ func TestViewIssuesKeyword(t *testing.T) {
 | 
				
			|||||||
		RepoID: repo.ID,
 | 
							RepoID: repo.ID,
 | 
				
			||||||
		Index:  1,
 | 
							Index:  1,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	issues.UpdateIssueIndexer(issue.ID)
 | 
						issues.UpdateIssueIndexer(context.Background(), issue.ID)
 | 
				
			||||||
	time.Sleep(time.Second * 1)
 | 
						time.Sleep(time.Second * 1)
 | 
				
			||||||
	const keyword = "first"
 | 
						const keyword = "first"
 | 
				
			||||||
	req := NewRequestf(t, "GET", "%s/issues?q=%s", repo.Link(), keyword)
 | 
						req := NewRequestf(t, "GET", "%s/issues?q=%s", repo.Link(), keyword)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user