bug(envd): PostInit spawns unbounded MMDS-poll goroutines — one per /init retry
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- go
- Domain
- backend, infrastructure
Research direction
Start in packages/envd/internal/api/init.go at PostInit, especially lines 209-213, and inspect how PollForMMDSOpts is launched and how initLock relates to it. Add the running-state guard described in the issue, then verify that repeated /init retries leave at most one MMDS poll goroutine active while allowing a later resume cycle to poll again.
Written by the indexing model from the issue text.
Description
Summary
PostInit unconditionally spawns a new goroutine on every call to poll MMDS. The orchestrator drives /init via an infinite retry loop, so when MMDS is not immediately reachable, goroutines accumulate inside the microVM without bound.
Root Cause
packages/envd/internal/api/init.go lines 209-213:
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
host.PollForMMDSOpts(ctx, a.mmdsChan, a.defaults.EnvVars)
}()
No guard prevents concurrent goroutine accumulation. initLock serialises body processing but the goroutine spawns after initLock.Release(1) so serialisation does not protect the spawn.
PollForMMDSOpts creates its own http.Client with DisableKeepAlives and ticks every 50ms issuing 2 HTTP requests per tick. Each goroutine lives up to 60 seconds.
Impact
At 100ms retry interval, 60 seconds of MMDS unavailability produces 600 concurrent goroutines, each making 40 connection-attempts/sec to 169.254.169.254 — 24000 TCP connections/sec total. This exhausts the VM ephemeral port range and can crash the envd control plane mid-resume.
Fix
Add an atomic.Bool guard to API struct and use CompareAndSwap in PostInit:
if a.mmdsPollRunning.CompareAndSwap(false, true) {
go func() {
defer a.mmdsPollRunning.Store(false)
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
host.PollForMMDSOpts(ctx, a.mmdsChan, a.defaults.EnvVars)
}()
}
Caps concurrent MMDS-poll goroutines at 1 while preserving re-poll across resume cycles.
- Dominant language
- Go
- Stars
- 1.6k
- Forks
- 438
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from e2b-dev/runtime
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
sandbox cache: StartRemoving state transition not broadcast, all allocations see stale Running state Open
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
Difficulty 1/5 Under an hour Newbie friendliness 86/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Similar issues
-
bug github_actions
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
registrystack/registry-stack#1393 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
JakeChampion/lang#10213 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
oasisprotocol/oasis-sdk#2523 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100