Skip to content

adarsh-sng/gomon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hotreload

hotreload watches a project folder, rebuilds on change, and restarts the server.

What It Does

  • Watches your source tree recursively
  • Debounces bursts of file changes
  • Runs your build command (optional)
  • Stops the old process and starts the new one
  • Keeps logs readable with simple terminal UI output

🛠️ Core Features & Edge Cases Handled

  • Process Group Isolation (-pgid): hotreload targets the entire Unix process group to ensure no orphaned zombie processes are left behind on restart.
  • Mid-Build Context Cancellation: If a file changes while compiling, the in-flight build is instantly cancelled via context.Context to save CPU cycles and start the fresh build immediately.
  • Crash-Loop Backoff: If a syntax error causes the server to crash in under 3 seconds, a backoff penalty is applied to prevent a 100% CPU infinite restart loop.
  • FD Watch Limit Fallback: Automatically maximizes the macOS soft FD limit at startup. For massive monorepos where OS limits are strictly capped, it gracefully degrades to a periodic polling engine for remaining directories.
  • Smart Debouncing: Rapid, simultaneous file saves (e.g., "Save All") are coalesced into a single rebuild trigger using a thread-safe timer.

Install

Option 1: Go install

go install github.com/adarsh-sng/gomon/cmd/hotreload@latest

OR (for now the repo is not public)

git clone https://github.com/adarsh-sng/gomon.git
cd gomon 
go install ./cmd/hotreload

This installs hotreload into $GOPATH/bin (usually ~/go/bin). Make sure it is in your PATH:

export PATH="$PATH:$HOME/go/bin"

Option 2: Makefile

git clone https://github.com/adarsh-sng/gomon.git
cd gomon
make build

hotreload requires two core arguments:

  • the root directory to watch (--root)
  • the execution command (--exec)
hotreload --root ./myproject \
  --build "go build -o ./bin/server ./cmd/server" \
  --exec "./bin/server"

Usage

General form:

hotreload --root <path> --exec "<run command>" [--build "<build command>"] [flags]

Example:

hotreload --root ./myproject \
  --build "go build -o ./bin/server ./cmd/server" \
  --exec "./bin/server"

Config

You can define defaults in .hotreload.yaml:

root: ./testserver
build: go build -o ./bin/server ./testserver
exec: ./bin/server
delay: 500ms
verbose: false

CLI flags override config values when both are set.

Flags

  • --root: directory to watch recursively (required)
  • --build: build command to run on change (optional)
  • --exec: run command for the built app (required)
  • --delay: debounce delay before rebuild, default 500ms
  • --verbose: enable debug logging

Notes

  • Use quotes around --build and --exec values.
  • Paths are resolved from the current working directory where you run hotreload.
  • If your executable path is relative, keep it consistent with your build output location.
  • .hotreload.yaml is loaded from --root (if set) or the current working directory.

Demo

Go demo server

make demo

Python demo server

make demo-python

Node demo server

make demo-node

Typical Workflows

Go project:

hotreload --root . \
  --build "go build -o ./bin/server ./cmd/server" \
  --exec "./bin/server"

Python project:

hotreload --root ./testserver-python \
  --exec "python3 ./testserver-python/app.py"

Node project:

hotreload --root ./testserver-node \
  --exec "node ./testserver-node/index.js"

Architecture (high level)

flowchart TD
  A[main.go] --> B[MaximizeFDLimit]
  A --> C[monitor.New]
  A --> D[debounce.New]
  A --> E[executor.New]

  C --> C1[fsnotify loop]
  C --> C2[poll loop]
  C1 --> F[events channel]
  C2 --> F

  F --> G[main event loop]
  G --> H[debounce trigger]
  H --> I[executor.Cycle]

  I --> J[kill process group]
  I --> K[run build]
  I --> L[start server]

  L --> M[server process]
  L --> N[cmd.Wait worker]
  N --> M
  B --> O[raise FD limit]
Loading
  • cmd/hotreload/main.go: CLI entrypoint, event loop, signal handling
  • internal/monitor: recursive watcher using fsnotify, with polling fallback when watch limits are hit
  • internal/debounce: coalesces rapid file changes before triggering rebuild
  • internal/executor: build + restart orchestration, crash loop backoff, process-group kill
  • internal/ui: colored output + spinner
  • internal/sysutil: OS helpers (FD limit bump on Unix)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors