enqueueResolved prepares the final path and working file before handing the download to the engine, so workers and lifecycle events agree on one stable destination.
(ctx context.Context, req *DownloadRequest, dispatch func(string, string, *ProbeResult) (string, error))
| 237 | // enqueueResolved prepares the final path and working file before handing the |
| 238 | // download to the engine, so workers and lifecycle events agree on one stable destination. |
| 239 | func (mgr *LifecycleManager) enqueueResolved(ctx context.Context, req *DownloadRequest, dispatch func(string, string, *ProbeResult) (string, error)) (string, string, error) { |
| 240 | if req.URL == "" { |
| 241 | return "", "", types.ErrURLRequired |
| 242 | } |
| 243 | if req.Path == "" { |
| 244 | return "", "", types.ErrDestRequired |
| 245 | } |
| 246 | |
| 247 | settings := mgr.GetSettings() |
| 248 | |
| 249 | // Throttle concurrent probes - acquire a semaphore slot before probing. |
| 250 | // If the context is cancelled (e.g., shutdown) we abort immediately. |
| 251 | if mgr.probeSem != nil { |
| 252 | select { |
| 253 | case <-mgr.probeSem: |
| 254 | // acquired |
| 255 | case <-ctx.Done(): |
| 256 | return "", "", fmt.Errorf("enqueue aborted before probe: %w", ctx.Err()) |
| 257 | } |
| 258 | defer func() { mgr.probeSem <- struct{}{} }() |
| 259 | } |
| 260 | |
| 261 | probe, probeErr := ProbeServerWithProxy(ctx, req.URL, req.Filename, req.Headers, settings.ToRuntimeConfig()) |
| 262 | if probeErr != nil { |
| 263 | // Distinguish between terminal client errors (invalid scheme, etc) and |
| 264 | // server-side rejections or timeouts that we can optimistically ignore. |
| 265 | var urlErr *url.Error |
| 266 | var isTerminal bool |
| 267 | if errors.As(probeErr, &urlErr) { |
| 268 | var opErr *net.OpError |
| 269 | isTerminal = !errors.As(probeErr, &opErr) && // not a network-layer error |
| 270 | strings.Contains(urlErr.Error(), "unsupported protocol scheme") |
| 271 | } |
| 272 | isTerminal = isTerminal || errors.Is(probeErr, ErrProbeRequestCreation) |
| 273 | |
| 274 | if isTerminal { |
| 275 | return "", "", probeErr |
| 276 | } |
| 277 | |
| 278 | utils.Debug("Lifecycle: Probe failed: %v - enqueueing with optimistic fallback metadata\n", probeErr) |
| 279 | // Probe failures are non-fatal for known server-side issues (403/405/500) or |
| 280 | // network timeouts: some servers reject or intermittently fail |
| 281 | // lightweight probe requests but still accept the actual download flow. |
| 282 | // Mark range support as "unknown, try it" by keeping size at zero and |
| 283 | // setting SupportsRange so the download path can attempt a concurrent |
| 284 | // bootstrap before falling back to single-stream mode. |
| 285 | probe = &ProbeResult{} |
| 286 | probe.SupportsRange = true |
| 287 | if req.Filename != "" { |
| 288 | probe.Filename = req.Filename |
| 289 | probe.DetectedFilename = req.Filename |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | isNameActive := mgr.buildIsNameActive() |
| 294 | |
| 295 | for attempt := 0; attempt < maxWorkingFileReservationAttempts; attempt++ { |
| 296 | if ctx.Err() != nil { |
no test coverage detected