Skip to content

Commit 6255f9e

Browse files
Auto-fallback to direct process when launchd fails
If launchctl bootstrap/load fails to start a server, automatically fall back to running it as a nohup background process. This handles newer macOS versions that may block launchd agent loading. Flow: kill port → try launchd → health check → if fail → nohup fallback User sees green checkmarks either way. Note shown if reboot won't auto-start. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6adb05a commit 6255f9e

1 file changed

Lines changed: 47 additions & 17 deletions

File tree

scripts/launchd-service.sh

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -104,33 +104,63 @@ cmd_install() {
104104

105105
local installed=0
106106

107+
# Check if a port responds to health check (with retries)
108+
wait_for_health() {
109+
local port=$1 retries=5
110+
for i in $(seq 1 $retries); do
111+
if curl -sf --connect-timeout 2 "http://localhost:${port}/health" >/dev/null 2>&1; then
112+
return 0
113+
fi
114+
sleep 1
115+
done
116+
return 1
117+
}
118+
119+
# Start a server directly as a background process (fallback when launchd fails)
120+
start_direct() {
121+
local name=$1 script=$2 port=$3
122+
# Kill any existing process on this port
123+
lsof -ti:${port} 2>/dev/null | xargs kill -9 2>/dev/null || true
124+
sleep 0.5
125+
nohup "$node_path" "${IBEX_DIR}/${script}" --http \
126+
>> "$HOME/.ibex-logs/${name}.log" \
127+
2>> "$HOME/.ibex-logs/${name}.err" &
128+
}
129+
107130
install_service() {
108131
local name=$1 script=$2 port=$3
109132
local plist
133+
134+
# Kill anything on this port first
135+
lsof -ti:${port} 2>/dev/null | xargs kill -9 2>/dev/null || true
136+
sleep 0.5
137+
138+
# Try launchd first (preferred — auto-restarts on crash and reboot)
110139
plist=$(generate_plist "$name" "$script" "$port")
111140
sed -i '' "s|/usr/local/bin/node|${node_path}|g" "$plist"
112-
# Modern macOS uses bootstrap/bootout; fall back to load/unload for older versions
113141
launchctl bootout "gui/$(id -u)" "$plist" 2>/dev/null || launchctl unload "$plist" 2>/dev/null
114142
launchctl bootstrap "gui/$(id -u)" "$plist" 2>/dev/null || launchctl load "$plist" 2>/dev/null
115-
# Verify the service actually started by checking the port
116-
sleep 1
117-
if curl -sf --connect-timeout 2 "http://localhost:${port}/health" >/dev/null 2>&1; then
118-
printf " ${GREEN}${NC} %s service running (port %s)\n" "$name" "$port"
143+
144+
if wait_for_health "$port"; then
145+
printf " ${GREEN}${NC} %s running (port %s, launchd)\n" "$name" "$port"
146+
installed=$((installed + 1))
147+
return
148+
fi
149+
150+
# Launchd failed — fall back to direct background process
151+
printf " ${YELLOW}!${NC} %s launchd failed, starting directly...\n" "$name"
152+
start_direct "$name" "$script" "$port"
153+
154+
if wait_for_health "$port"; then
155+
printf " ${GREEN}${NC} %s running (port %s, background)\n" "$name" "$port"
156+
printf " ${YELLOW}Note:${NC} Won't auto-start after reboot. Run ~/IBEX/start.sh\n"
119157
installed=$((installed + 1))
120158
else
121-
# Give it a bit more time — node startup can be slow
122-
sleep 2
123-
if curl -sf --connect-timeout 2 "http://localhost:${port}/health" >/dev/null 2>&1; then
124-
printf " ${GREEN}${NC} %s service running (port %s)\n" "$name" "$port"
125-
installed=$((installed + 1))
126-
else
127-
printf " ${RED}${NC} %s service failed to start on port %s\n" "$name" "$port"
128-
printf " Check log: cat ~/.ibex-logs/${name}.err\n"
129-
if [ -f "$HOME/.ibex-logs/${name}.err" ] && [ -s "$HOME/.ibex-logs/${name}.err" ]; then
130-
printf " Last error: %s\n" "$(tail -1 "$HOME/.ibex-logs/${name}.err")"
131-
fi
132-
failed=$((failed + 1))
159+
printf " ${RED}${NC} %s failed to start on port %s\n" "$name" "$port"
160+
if [ -f "$HOME/.ibex-logs/${name}.err" ] && [ -s "$HOME/.ibex-logs/${name}.err" ]; then
161+
printf " Last error: %s\n" "$(tail -1 "$HOME/.ibex-logs/${name}.err")"
133162
fi
163+
failed=$((failed + 1))
134164
fi
135165
}
136166

0 commit comments

Comments
 (0)