···204204func populateIssueIndexer(ctx context.Context) {
205205 ctx, _, finished := process.GetManager().AddTypedContext(ctx, "Service: PopulateIssueIndexer", process.SystemProcessType, true)
206206 defer finished()
207207- if err := PopulateIssueIndexer(ctx, true); err != nil {
207207+ ctx = contextWithKeepRetry(ctx) // keep retrying since it's a background task
208208+ if err := PopulateIssueIndexer(ctx); err != nil {
208209 log.Error("Issue indexer population failed: %v", err)
209210 }
210211}
211212212212-func PopulateIssueIndexer(ctx context.Context, keepRetrying bool) error {
213213+func PopulateIssueIndexer(ctx context.Context) error {
213214 for page := 1; ; page++ {
214215 select {
215216 case <-ctx.Done():
···232233 }
233234234235 for _, repo := range repos {
235235- for {
236236- select {
237237- case <-ctx.Done():
238238- return fmt.Errorf("shutdown before completion: %w", ctx.Err())
239239- default:
240240- }
241241- if err := updateRepoIndexer(ctx, repo.ID); err != nil {
242242- if keepRetrying && ctx.Err() == nil {
243243- log.Warn("Retry to populate issue indexer for repo %d: %v", repo.ID, err)
244244- continue
245245- }
246246- return fmt.Errorf("populate issue indexer for repo %d: %v", repo.ID, err)
247247- }
248248- break
236236+ if err := updateRepoIndexer(ctx, repo.ID); err != nil {
237237+ return fmt.Errorf("populate issue indexer for repo %d: %v", repo.ID, err)
249238 }
250239 }
251240 }
···259248}
260249261250// UpdateIssueIndexer add/update an issue to the issue indexer
262262-func UpdateIssueIndexer(issueID int64) {
263263- if err := updateIssueIndexer(issueID); err != nil {
251251+func UpdateIssueIndexer(ctx context.Context, issueID int64) {
252252+ if err := updateIssueIndexer(ctx, issueID); err != nil {
264253 log.Error("Unable to push issue %d to issue indexer: %v", issueID, err)
265254 }
266255}
+34-12
modules/indexer/issues/util.go
···127127 return fmt.Errorf("issue_model.GetIssueIDsByRepoID: %w", err)
128128 }
129129 for _, id := range ids {
130130- if err := updateIssueIndexer(id); err != nil {
130130+ if err := updateIssueIndexer(ctx, id); err != nil {
131131 return err
132132 }
133133 }
134134 return nil
135135}
136136137137-func updateIssueIndexer(issueID int64) error {
138138- return pushIssueIndexerQueue(&IndexerMetadata{ID: issueID})
137137+func updateIssueIndexer(ctx context.Context, issueID int64) error {
138138+ return pushIssueIndexerQueue(ctx, &IndexerMetadata{ID: issueID})
139139}
140140141141func deleteRepoIssueIndexer(ctx context.Context, repoID int64) error {
···148148 if len(ids) == 0 {
149149 return nil
150150 }
151151- return pushIssueIndexerQueue(&IndexerMetadata{
151151+ return pushIssueIndexerQueue(ctx, &IndexerMetadata{
152152 IDs: ids,
153153 IsDelete: true,
154154 })
155155}
156156157157-func pushIssueIndexerQueue(data *IndexerMetadata) error {
157157+type keepRetryKey struct{}
158158+159159+// contextWithKeepRetry returns a context with a key indicating that the indexer should keep retrying.
160160+// Please note that it's for background tasks only, and it should not be used for user requests, or it may cause blocking.
161161+func contextWithKeepRetry(ctx context.Context) context.Context {
162162+ return context.WithValue(ctx, keepRetryKey{}, true)
163163+}
164164+165165+func pushIssueIndexerQueue(ctx context.Context, data *IndexerMetadata) error {
158166 if issueIndexerQueue == nil {
159167 // Some unit tests will trigger indexing, but the queue is not initialized.
160168 // It's OK to ignore it, but log a warning message in case it's not a unit test.
···162170 return nil
163171 }
164172165165- err := issueIndexerQueue.Push(data)
166166- if errors.Is(err, queue.ErrAlreadyInQueue) {
167167- return nil
168168- }
169169- if errors.Is(err, context.DeadlineExceeded) {
170170- log.Warn("It seems that issue indexer is slow and the queue is full. Please check the issue indexer or increase the queue size.")
173173+ for {
174174+ select {
175175+ case <-ctx.Done():
176176+ return ctx.Err()
177177+ default:
178178+ }
179179+ err := issueIndexerQueue.Push(data)
180180+ if errors.Is(err, queue.ErrAlreadyInQueue) {
181181+ return nil
182182+ }
183183+ if errors.Is(err, context.DeadlineExceeded) { // the queue is full
184184+ log.Warn("It seems that issue indexer is slow and the queue is full. Please check the issue indexer or increase the queue size.")
185185+ if ctx.Value(keepRetryKey{}) == nil {
186186+ return err
187187+ }
188188+ // It will be better to increase the queue size instead of retrying, but users may ignore the previous warning message.
189189+ // However, even it retries, it may still cause index loss when there's a deadline in the context.
190190+ log.Debug("Retry to push %+v to issue indexer queue", data)
191191+ continue
192192+ }
193193+ return err
171194 }
172172- return err
173195}