Skip to content

fix(run): scope micro run as a dev tool and harden the dev loop - #4875

Merged
asim merged 1 commit into
masterfrom
claude/micro-run-dev-tool
Aug 2, 2026
Merged

fix(run): scope micro run as a dev tool and harden the dev loop#4875
asim merged 1 commit into
masterfrom
claude/micro-run-dev-tool

Conversation

@asim

@asim asim commented Aug 2, 2026

Copy link
Copy Markdown
Member

Why

micro run is the local development inner loop — build, run, hot-reload — not a production runtime. There's no daemon; processes stop when it exits. This makes that explicit and fixes real dev-UX bugs in the loop.

Changes

Correctness / UX

  • Clean shutdown. The new-service scanner goroutine read the same signal channel as the main wait. A signal is delivered to only one receiver, so the scanner could steal Ctrl-C and hang teardown. Background goroutines now use a dedicated shutdown channel, and the services/servicesByDir state is guarded by a mutex (also fixing a data race on the slice during shutdown).
  • Hot reload no longer takes a service offline on a compile error. Reload now builds into a temp binary first and only stops + swaps + restarts if the build succeeds. On failure the previous version keeps serving and the build error is printed — a typo never kills your running service.
  • Log buffer. Raised the per-service log scanner buffer (64KB→1MB max line) so long lines (JSON logs, stack traces) no longer overflow it and silently drop that service's logs from then on.

Honest framing (dev tool, no daemon)

  • micro run --help now states plainly it's a local dev tool with no daemon, and points to systemd / Docker / Kubernetes for production.
  • The micro run guide removes the fictional micro logs / micro status / micro stop commands (no such commands exist), describes the real lifecycle (Ctrl-C, ~/micro/logs/*.log), and adds a "Going to production" section.

Verification

  • go build ./cmd/micro/..., go vet ./cmd/micro/run/, and go test -race ./cmd/micro/run/... all pass.
  • micro run --help reflects the dev-tool framing.

Not included (pending a separate decision)

We're still deciding whether micro server should exist as a distinct command or be folded into a single deployable "gateway." The docs here are intentionally neutral on that naming — this PR doesn't entrench micro server. The gateway/command-surface change will be its own PR.

🤖 Generated with Claude Code


Generated by Claude Code

micro run is the local development inner loop, not a production runtime.
Make that explicit and fix real dev-UX bugs:

- Clean shutdown: the new-service scanner shared the signal channel with
  the main wait; a signal goes to one receiver, so it could steal Ctrl-C
  and hang teardown. Give background goroutines a dedicated shutdown
  channel and guard the services slice with a mutex (also fixes a data
  race on that slice during shutdown).
- Hot reload no longer takes a service offline on a compile error: build
  into a temp binary first and only swap+restart if the build succeeds;
  on failure the previous version keeps serving and the error is printed.
- Raise the log scanner buffer so long lines (JSON logs, stack traces)
  no longer overflow it and silently drop a services logs.
- Help text and the micro run guide now state plainly it is a dev tool
  with no daemon, and point to systemd/Docker/Kubernetes for production.
  Remove the guides fictional micro logs/status/stop commands (no such
  commands exist) and describe the real lifecycle (Ctrl-C, log files).
Copilot AI review requested due to automatic review settings August 2, 2026 10:37

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 218bb4f488

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/micro/run/run.go
// caller reports the error and the previous version keeps serving.
func (s *serviceProcess) reload(logDir string) error {
newBin := s.binPath + ".new"
if err := s.build(newBin); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Prevent reload from launching after shutdown

When Ctrl-C or SIGTERM arrives while this out-of-lock build is running, teardown can stop the old process and finish before the build completes. The reload goroutine then resumes, sees nothing running in s.stop(), swaps the binary, and calls s.launch, leaving a service process alive after micro run exits. watch.Stop() does not join the event-handler goroutine, so reloads need to be coordinated with shutdown or awaited before teardown returns.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR reframes micro run explicitly as a local development inner-loop tool and hardens its hot-reload supervision behavior to improve dev UX and shutdown correctness.

Changes:

  • Updates micro run service supervision to avoid signal-stealing during shutdown, reduce races around service discovery, and improve hot reload behavior (build-then-swap so compile errors don’t take services offline).
  • Increases per-service log scan buffer limits to better handle long log lines without dropping output.
  • Revises the micro run documentation/help text to reflect the real lifecycle (no daemon) and provide production guidance.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
internal/website/content/en/docs/guides/micro-run.md Updates the guide to clearly position micro run as a dev tool (no daemon), removes fictional commands, and adds a production-oriented section.
cmd/micro/run/run.go Hardens the dev loop: build-then-swap reload behavior, dedicated shutdown signaling, mutex-guarded service tracking, and larger log scanner buffer.
Suppressed comments (2)

cmd/micro/run/run.go:474

  • The new-service scanner can still start services after shutdown begins: if the ticker.C case is already selected when shutdown is closed, the goroutine will append to services and then sp.start() even during teardown. In the worst case this can leave a newly started process running after micro run exits (e.g., if it starts after the stop-snapshot loop has already run). Add a shutdown check before starting each discovered service to ensure no new processes are launched once teardown begins.
					for _, sp := range newSvcs {
						watch.AddDir(sp.dir)
						if err := sp.start(logsDir); err != nil {
							fmt.Fprintf(os.Stderr, "[%s] %v\n", sp.name, err)
							continue
						}
						fmt.Printf("\n  \033[32m●\033[0m %s \033[2m(new)\033[0m\n", sp.name)

cmd/micro/run/run.go:121

  • The log streaming goroutine never checks scanner.Err(). If scanning stops due to an error (e.g., a line still exceeds the max token size), logs will stop without any indication even though this change is explicitly trying to avoid “silent” log loss. Emit the scan error so users know why logs stopped for a service.
		for scanner.Scan() {
			line := scanner.Text()
			fmt.Printf("%s[%s]%s %s\n", color, name, colorReset, line)
			_, _ = logFile.WriteString("[" + name + "] " + line + "\n")
		}
	}(s.name, s.color, pr, logFile)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/micro/run/run.go
Comment on lines 190 to +194
s.stop()
return s.start(logDir)
if err := os.Rename(newBin, s.binPath); err != nil {
return fmt.Errorf("swap binary: %w", err)
}
return s.launch(logDir)
@asim
asim merged commit 80aafc3 into master Aug 2, 2026
15 checks passed
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.

3 participants