Refresh fetches fresh PR data for a batch of stale rows. Rows are grouped internally by (ownerID, origin) so that provider and token resolution happen once per group. HTTP calls within and across groups run concurrently, bounded by the Refresher's concurrency limit. A top-level error is returned on
( ctx context.Context, requests []RefreshRequest, )
| 136 | // returned RefreshResult slice (one per input request, same |
| 137 | // order). |
| 138 | func (r *Refresher) Refresh( |
| 139 | ctx context.Context, |
| 140 | requests []RefreshRequest, |
| 141 | ) ([]RefreshResult, error) { |
| 142 | results := make([]RefreshResult, len(requests)) |
| 143 | for i, req := range requests { |
| 144 | results[i].Request = req |
| 145 | } |
| 146 | |
| 147 | // Group request indices by (ownerID, origin). |
| 148 | groups := make(map[groupKey][]int) |
| 149 | for i, req := range requests { |
| 150 | key := groupKey{ |
| 151 | ownerID: req.OwnerID, |
| 152 | origin: req.Row.GitRemoteOrigin, |
| 153 | } |
| 154 | groups[key] = append(groups[key], i) |
| 155 | } |
| 156 | |
| 157 | // Pre-resolve providers and tokens sequentially. This is |
| 158 | // fast (DB + in-memory config lookups) and avoids |
| 159 | // duplicate resolution for rows in the same group. |
| 160 | var resolved []resolvedGroup |
| 161 | for key, indices := range groups { |
| 162 | provider := r.providers(ctx, key.origin) |
| 163 | if provider == nil { |
| 164 | err := xerrors.Errorf("no provider for origin %q", key.origin) |
| 165 | for _, i := range indices { |
| 166 | results[i].Error = err |
| 167 | } |
| 168 | continue |
| 169 | } |
| 170 | |
| 171 | token, err := r.tokens(ctx, key.ownerID, key.origin) |
| 172 | if err != nil { |
| 173 | err = xerrors.Errorf("resolve token: %w", err) |
| 174 | } else if token == nil || len(*token) == 0 { |
| 175 | err = ErrNoTokenAvailable |
| 176 | } |
| 177 | if err != nil { |
| 178 | for _, i := range indices { |
| 179 | results[i].Error = err |
| 180 | } |
| 181 | continue |
| 182 | } |
| 183 | |
| 184 | resolved = append(resolved, resolvedGroup{ |
| 185 | provider: provider, |
| 186 | token: *token, |
| 187 | indices: indices, |
| 188 | }) |
| 189 | } |
| 190 | |
| 191 | // Process all HTTP calls concurrently with a shared |
| 192 | // semaphore. Each group tracks rate-limit errors |
| 193 | // independently so that a limit hit on one provider |
| 194 | // doesn't stall requests to other providers. |
| 195 | sem := make(chan struct{}, r.concurrency) |