Skip to content

BC artifact downloads from bcartifacts AFD endpoint highly variable on hosted CI runners (30s → 5-6 min) #4119

Description

Symptom

When downloading BC artifacts from bcartifacts-exdbf9fwegejdqak.b02.azurefd.net on hosted CI runners (GitHub Actions ubuntu-latest, also reproduced on hosted Azure DevOps agents), wall-clock download time varies wildly between runs against the same artifact and from the same runner pool:

  • Fast path (typical): ~30 s for app (~850 MB) + platform (~1.3 GB) — i.e. ~70-90 MB/s aggregate.
  • Slow path (occasional): 5-6 min for the same payload — effective rate drops to <5 MB/s.

There's no error, no retry, no timeout — the GETs just complete slowly. So curl --retry doesn't help: the connection is "successful", just slow.

Evidence

A recent run on a Microsoft-hosted ubuntu-latest runner that hit the fast path:

[artifacts] App URL:      https://bcartifacts-exdbf9fwegejdqak.b02.azurefd.net/sandbox/27.5.46862.48612/w1
[artifacts] Platform URL: https://bcartifacts-exdbf9fwegejdqak.b02.azurefd.net/sandbox/27.5.46862.48612/platform
[artifacts] Downloading app + platform in parallel...
[artifacts] Downloaded: app=856M platform=1.3G in 23546ms (~88 MB/s)
[artifacts] Extracting app...
[artifacts] Extracted in 27094ms | Total: 50654ms | Disk: 3.0G

So the network and runner are clearly capable of ~88 MB/s. But other runs against the same URL on the same runner type take 5-6 min for the same bytes.

Download shape

Two concurrent HTTP/1.1 GETs (one for <type>/<version>/<country>, one for <type>/<version>/platform), each on a single TCP connection:

curl -sSL --retry 3 --retry-all-errors --http1.1 "$APP_URL"      -o app.zip      &
curl -sSL --retry 3 --retry-all-errors --http1.1 "$PLATFORM_URL" -o platform.zip &
wait

--http1.1 is intentional — without it, HTTP/2 multiplexing on AFD made things consistently worse in our testing.

Suspected cause

The host is Azure Front Door (.azurefd.net), which has documented per-route knobs:

  • responseTimeoutSeconds (origin-fetch + total response budget)
  • per-connection bandwidth caps / origin pool sizing
  • origin fetch behaviour on cold cache miss

The slow runs have the shape of a per-connection bandwidth cap that's set tight, or an origin-fetch timeout that's just barely large enough on the fast path and falls back to a slower path on the slow one. Since we use one connection per file, there's no way for the client to compensate when AFD throttles that connection.

What's been tried client-side (and why it doesn't fix it)

  • ✅ Forcing HTTP/1.1 — helps, but doesn't eliminate the slow path
  • ✅ Parallelising app + platform — lifts aggregate, but each connection is still capped
  • curl --retry — the slow connection completes "successfully", so retry never triggers
  • ❌ Range-request parallelism (4-8 byte ranges per file) would multiply throughput on the slow path, but it's a non-trivial rewrite and shouldn't be necessary if AFD limits are right

The ask

Could the AFD route limits for bcartifacts-exdbf9fwegejdqak.b02.azurefd.net be reviewed? Specifically:

  1. responseTimeoutSeconds and origin-fetch timeout for the /sandbox/<version>/... and /onprem/<version>/... routes
  2. Whether there's a per-connection bandwidth cap, and if so what it's set to
  3. Whether cold-cache misses on these blobs go through a slower origin path that could be warmed up or cached more aggressively

Stefan mentioned in our discussion that he remembers a previous request like this leading to some AFD values being adjusted — same thing, please. 🙂

Affects

  • navcontainerhelper artifact downloads (same URL, same shape)
  • The download-artifacts.sh used by StefanMaron/MsDyn365Bc.On.Linux (Linux BC runtime), which is what surfaced this for me
  • Likely anyone hitting bcartifacts-exdbf9fwegejdqak.b02.azurefd.net from CI

cc Freddy Kristiansen (@freddydk)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions