Skip to content

feat: channel-based image notifications + erofs default#105

Merged
hiroTamada merged 3 commits intomainfrom
feat/channel-notify-erofs-default
Feb 17, 2026
Merged

feat: channel-based image notifications + erofs default#105
hiroTamada merged 3 commits intomainfrom
feat/channel-notify-erofs-default

Conversation

@hiroTamada
Copy link
Contributor

@hiroTamada hiroTamada commented Feb 17, 2026

Summary

  • Replace polling with channel-based notifications: waitForImageReady() in the builds manager previously polled every 500ms (up to 120 attempts). Now it delegates to imageManager.WaitForReady(), which uses a channel-based pub/sub system for instant notification when image conversion completes. Subscribes BEFORE re-checking status to avoid TOCTOU races. Includes a 30s retry loop for the initial GetImage call to handle the race where WaitForReady is called before the registry's async ImportLocalImage has executed.
  • Switch default image format to erofs: Changes DefaultImageFormat from ext4 to erofs (LZ4-compressed read-only filesystem) for smaller, faster rootfs images. Updates ImageDigestPath from rootfs.ext4 to rootfs.erofs. VM init now tries erofs first with ext4 fallback for backward compatibility with legacy images.

Files changed

File Change
lib/images/manager.go Add StatusEvent, WaitForReady(), subscribe/unsubscribe/notify methods, readySubscribers map
lib/builds/manager.go Replace polling loop with delegation to WaitForReady()
lib/builds/manager_test.go Add WaitForReady to mock, add sync.RWMutex for thread safety
lib/builds/race_test.go Use mutex-protected access for concurrent test updates
lib/images/disk.go Change DefaultImageFormat to FormatErofs
lib/paths/paths.go Change rootfs.ext4 to rootfs.erofs
lib/images/storage.go Update comment
lib/system/init/mount.go erofs-first mount with ext4 fallback

Test plan

  • go test -race ./lib/builds/... passes (including race detector)
  • go build ./... compiles successfully
  • go vet passes on all modified packages
  • End-to-end build test: submitted build via API, image pushed to registry, erofs conversion completed, build reported status: "ready"
  • Verified rootfs.erofs files created with correct EROFS filesystem + LZ4 compression (file command confirms)
  • Verify VM boots from erofs image (instance creation)
  • Verify legacy ext4 images still mount via fallback path

🤖 Generated with Claude Code


Note

Medium Risk
Touches image lifecycle synchronization and changes on-disk rootfs format/default mounting behavior; failures would surface as builds that hang/fail to become ready or instances that can’t boot/mount images.

Overview
Builds no longer “go ready” while image conversion is still in flight: builds.manager.waitForImageReady drops polling and delegates to a new images.Manager.WaitForReady, which uses a digest-keyed pub/sub to notify waiters on ready/failed terminal states (with a short existence-poll to handle async ImportLocalImage).

Image export defaults change from ext4 to compressed erofs on Linux, while keeping ext4 on Darwin; paths now select rootfs.erofs vs rootfs.ext4 by OS, and init mounting tries erofs first with ext4 fallback. Tests/mocks were updated for the new interface and to add thread-safe status mutation in concurrency/race tests.

Written by Cursor Bugbot for commit d02edc1. This will update automatically on new commits. Configure here.

… erofs

Replace the 500ms polling loop in waitForImageReady() with a channel-based
pub/sub notification system on the image manager, reducing build-to-SSE lag.
Switch the default image format from ext4 to erofs (LZ4-compressed read-only
filesystem) for faster, smaller rootfs images. The VM init mounts erofs first
with an ext4 fallback for backward compatibility with legacy images.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Collaborator

@sjmiller609 sjmiller609 left a comment

Choose a reason for hiding this comment

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

nice. and existing tests seem to cover risks well

// Notify subscribers of terminal status
if status == StatusReady || status == StatusFailed {
m.notifyReady(ref.DigestHex(), status, err)
}
Copy link

Choose a reason for hiding this comment

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

Dual notification paths risk duplicate subscriber notifications

Low Severity

notifyReady for StatusReady is called directly in buildImage at line 302 and also conditionally in updateStatusByDigest at line 337–339. Currently no double notification occurs because updateStatusByDigest is never called with StatusReady, making the StatusReady guard at line 337 dead code. However, having two separate notification paths for the same event is fragile — if the success flow is ever refactored to use updateStatusByDigest, subscribers would receive duplicate events on a buffered channel of size 1, causing the second send to be silently dropped.

Additional Locations (1)

Fix in Cursor Fix in Web

hiroTamada and others added 2 commits February 17, 2026 14:40
… erofs

Replace the 500ms polling loop in waitForImageReady() with a channel-based
pub/sub notification system on the image manager, reducing build-to-SSE lag.
Switch the default image format from ext4 to erofs (LZ4-compressed read-only
filesystem) for faster, smaller rootfs images. The VM init mounts erofs first
with an ext4 fallback for backward compatibility with legacy images.

Log which filesystem type (erofs or ext4) was actually mounted so operators
can verify erofs is being used and diagnose fallback scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Make DefaultImageFormat platform-aware:
- Linux: erofs (compressed, smaller images)
- Darwin: ext4 (VZ kernel doesn't have erofs support)

This fixes the Darwin CI failure where VMs couldn't mount erofs rootfs.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

if event.Status == StatusReady {
return nil
}
return fmt.Errorf("image conversion failed")
Copy link

Choose a reason for hiding this comment

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

StatusEvent.Err is populated but never consumed

Medium Severity

The StatusEvent.Err field is populated with the actual conversion error in notifyReady but never read by WaitForReady, which only checks event.Status and returns a generic "image conversion failed" string. The original error (e.g., "convert to erofs: mkfs.erofs failed: …") is silently discarded, making production debugging harder. The Err field is effectively dead code.

Additional Locations (1)

Fix in Cursor Fix in Web

@hiroTamada hiroTamada merged commit 46d281b into main Feb 17, 2026
6 checks passed
@hiroTamada hiroTamada deleted the feat/channel-notify-erofs-default branch February 17, 2026 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments