Skip to content

fix(envd): replace time.Sleep with ticker in ScanAndBroadcast for prompt shutdown - #3374

Merged
arkamar merged 4 commits into
e2b-dev:mainfrom
AdaAibaby:fix/port-scanner-context-aware-sleep
Jul 24, 2026
Merged

fix(envd): replace time.Sleep with ticker in ScanAndBroadcast for prompt shutdown#3374
arkamar merged 4 commits into
e2b-dev:mainfrom
AdaAibaby:fix/port-scanner-context-aware-sleep

Conversation

@AdaAibaby

@AdaAibaby AdaAibaby commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

fixes #3356

Problem

ScanAndBroadcast() used time.Sleep inside a default select case:

select {
case <-s.scanExit:
    return
default:
    time.Sleep(s.period)  // ← Destroy() is invisible here
}

Destroy() closes scanExit, but the goroutine only checks scanExit at the top of each iteration — before the sleep starts. Once time.Sleep is entered, a concurrent Destroy() call is not noticed until the sleep completes. With portScannerInterval = 1 s, every envd shutdown was delayed by up to 1 second waiting for the port scanner goroutine.

Fix

Replace time.Sleep with time.NewTicker so scanExit and the tick interval are waited on simultaneously in a single select:

func (s *Scanner) ScanAndBroadcast() {
    ticker := time.NewTicker(s.period)
    defer ticker.Stop()

    for {
        processes, _ := net.Connections("tcp")
        for _, sub := range s.subs.Items() {
            sub.Signal(processes)
        }
        select {
        case <-s.scanExit:
            return          // exits immediately on Destroy()
        case <-ticker.C:
        }
    }
}

Destroy() now unblocks the goroutine instantly, regardless of how far into the current interval it is.

Using a Ticker (instead of time.After) also avoids allocating a new timer object on every loop iteration.

Tests

Two new tests in scan_test.go:

  • TestScanAndBroadcastDestroyExitsPromptly — creates a scanner with a 5 s period, lets it enter the select block, calls Destroy(), and asserts the goroutine exits within 200 ms (not after 5 s).
  • TestScanAndBroadcastDestroyBeforeSleep — calls Destroy() before ScanAndBroadcast starts, verifying the goroutine still exits promptly.

Both pass in < 100 ms total.

/cc @jakubno @dobrac @ValentaTomas

arkamar added 3 commits July 24, 2026 15:09
The tests depended on wall-clock timing (small exit budgets around real
/proc scans via net.Connections), making them flaky on slow or loaded
machines. The sleep-to-ticker change in ScanAndBroadcast is a
straightforward select on scanExit that is verifiable by inspection, so
the tests are not worth the flake risk.
The added line described the implementation rather than the contract;
keep the function comment as it was on main.

@arkamar arkamar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the change, LGTM. I think the tests are not needed for this, as they could easily become flaky, at least as they were written. The timing assertions could false-fail on a loaded runner. The fix itself is a straightforward select on scanExit, verifiable by inspection.

I removed the additional comment from ScanAndBroadcast() as it described the implementation detail rather than the contract, and the original one-liner still covers what the function does.

I pushed these changes directly to your branch, along with the envd version bump to 0.6.11. The remaining diff is just the sleep→ticker change, which is exactly what we want here.

@arkamar
arkamar merged commit 002fd9f into e2b-dev:main Jul 24, 2026
34 checks passed
charlie-e2b pushed a commit that referenced this pull request Jul 29, 2026
🤖 I have created a release *beep* *boop*
---


## 0.0.1 (2026-07-29)


### Features

* **envd:** add --no-cgroups flag to disable cgroup management
([#2811](#2811))
([e10814c](e10814c))
* **envd:** add optional EntryInfo to watch FilesystemEvent
([#2930](#2930))
([bbbc7c8](bbbc7c8))
* **envd:** allow opting into watching network mounts
([#2982](#2982))
([9799dd0](9799dd0))
* **envd:** give envd realtime IO priority, reset for user processes
([#2681](#2681))
([f4bd1b2](f4bd1b2))
* **envd:** split collapse stats into real migrations vs already-huge
([#3021](#3021))
([0d77614](0d77614))
* **envd:** support user-defined file metadata via xattrs
([#2732](#2732))
([da8fbe4](da8fbe4))
* freeze user cgroup across pause/resume to keep envd /init responsive
([#2688](#2688))
([eceb741](eceb741))
* **orch:** collapse envd's heap into 2 MiB hugepages before pause to
cut cold-resume faults
([#2997](#2997))
([6677f73](6677f73))
* **orch:** distro-aware template base-image provisioning
([#3411](#3411))
([f8c7b5b](f8c7b5b))


### Bug Fixes

* added envd to artifact repository
([#3432](#3432))
([6c4f0e2](6c4f0e2))
* correct 3 CVES ([#3218](#3218))
([076823b](076823b))
* **envd:** avoid Start deadlock after request cancellation
([#3256](#3256))
([04317f8](04317f8))
* **envd:** bound the in-memory logs queue
([#2676](#2676))
([05c9939](05c9939))
* **envd:** discard output when no subscriber is connected
([#2639](#2639))
([8cf1795](8cf1795))
* **envd:** fall back to lazy unmount when forced NFS umount fails
([#2683](#2683))
([5346a0d](5346a0d))
* **envd:** ignore closed pty read errors
([#2769](#2769))
([6118672](6118672))
* **envd:** include suppressed count in exporter error logs
([#2680](#2680))
([35c1141](35c1141))
* **envd:** make /init lock ctx-aware to prevent retry pile-up
([#2702](#2702))
([173afd4](173afd4))
* **envd:** make CA install lock ctx-aware
([#2690](#2690))
([83ee89f](83ee89f))
* **envd:** replace env vars in /init instead of merging
([#2706](#2706))
([1b52e9a](1b52e9a))
* **envd:** replace time.Sleep with ticker in ScanAndBroadcast for
prompt shutdown ([#3374](#3374))
([002fd9f](002fd9f))
* **envd:** self-heal MMDS routing on /init lookup failure
([#2701](#2701))
([90944d5](90944d5))
* **envd:** stop freezing socat cgroup across pause/resume
([#2923](#2923))
([8b6f2b9](8b6f2b9))
* **envd:** stop misleading CA install cancel errors on rapid /init
([#3206](#3206))
([91d09e4](91d09e4))
* **envd:** suppress repeat MMDS poll failures
([#2678](#2678))
([73d691a](73d691a))
* **envd:** tolerate busy tmpfs cleanup in tests
([#2938](#2938))
([a485834](a485834))
* **envd:** use constant-time comparison for signature validation
([#3145](#3145))
([fcf92fa](fcf92fa))
* **envd:** use WithoutCancel for CA cleanup goroutine ctx
([#3207](#3207))
([ee7bf84](ee7bf84))


### Performance Improvements

* **envd:** stop logging streamed payload content
([#2755](#2755))
([db3868c](db3868c))
* **sandbox:** keep envd logging out of journald
([#2675](#2675))
([f6943ca](f6943ca))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>
jakubno pushed a commit that referenced this pull request Aug 3, 2026
🤖 I have created a release *beep* *boop*
---


## 0.0.1 (2026-07-29)


### Features

* **envd:** add --no-cgroups flag to disable cgroup management
([#2811](#2811))
([e10814c](e10814c))
* **envd:** add optional EntryInfo to watch FilesystemEvent
([#2930](#2930))
([bbbc7c8](bbbc7c8))
* **envd:** allow opting into watching network mounts
([#2982](#2982))
([9799dd0](9799dd0))
* **envd:** give envd realtime IO priority, reset for user processes
([#2681](#2681))
([f4bd1b2](f4bd1b2))
* **envd:** split collapse stats into real migrations vs already-huge
([#3021](#3021))
([0d77614](0d77614))
* **envd:** support user-defined file metadata via xattrs
([#2732](#2732))
([da8fbe4](da8fbe4))
* freeze user cgroup across pause/resume to keep envd /init responsive
([#2688](#2688))
([eceb741](eceb741))
* **orch:** collapse envd's heap into 2 MiB hugepages before pause to
cut cold-resume faults
([#2997](#2997))
([6677f73](6677f73))
* **orch:** distro-aware template base-image provisioning
([#3411](#3411))
([1abece1](1abece1))


### Bug Fixes

* added envd to artifact repository
([#3432](#3432))
([b7024ba](b7024ba))
* correct 3 CVES ([#3218](#3218))
([076823b](076823b))
* **envd:** avoid Start deadlock after request cancellation
([#3256](#3256))
([04317f8](04317f8))
* **envd:** bound the in-memory logs queue
([#2676](#2676))
([05c9939](05c9939))
* **envd:** discard output when no subscriber is connected
([#2639](#2639))
([8cf1795](8cf1795))
* **envd:** fall back to lazy unmount when forced NFS umount fails
([#2683](#2683))
([5346a0d](5346a0d))
* **envd:** ignore closed pty read errors
([#2769](#2769))
([6118672](6118672))
* **envd:** include suppressed count in exporter error logs
([#2680](#2680))
([35c1141](35c1141))
* **envd:** make /init lock ctx-aware to prevent retry pile-up
([#2702](#2702))
([173afd4](173afd4))
* **envd:** make CA install lock ctx-aware
([#2690](#2690))
([83ee89f](83ee89f))
* **envd:** replace env vars in /init instead of merging
([#2706](#2706))
([1b52e9a](1b52e9a))
* **envd:** replace time.Sleep with ticker in ScanAndBroadcast for
prompt shutdown ([#3374](#3374))
([002fd9f](002fd9f))
* **envd:** self-heal MMDS routing on /init lookup failure
([#2701](#2701))
([90944d5](90944d5))
* **envd:** stop freezing socat cgroup across pause/resume
([#2923](#2923))
([8b6f2b9](8b6f2b9))
* **envd:** stop misleading CA install cancel errors on rapid /init
([#3206](#3206))
([91d09e4](91d09e4))
* **envd:** suppress repeat MMDS poll failures
([#2678](#2678))
([73d691a](73d691a))
* **envd:** tolerate busy tmpfs cleanup in tests
([#2938](#2938))
([a485834](a485834))
* **envd:** use constant-time comparison for signature validation
([#3145](#3145))
([fcf92fa](fcf92fa))
* **envd:** use WithoutCancel for CA cleanup goroutine ctx
([#3207](#3207))
([ee7bf84](ee7bf84))


### Performance Improvements

* **envd:** stop logging streamed payload content
([#2755](#2755))
([db3868c](db3868c))
* **sandbox:** keep envd logging out of journald
([#2675](#2675))
([f6943ca](f6943ca))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(envd): port scanner ScanAndBroadcast uses time.Sleep instead of select+ticker, delaying shutdown

2 participants