Skip to content

Instantly share code, notes, and snippets.

@regiellis
Last active February 20, 2025 21:45
Show Gist options
  • Save regiellis/7406d62ac47b6e9926b3231d34d0a553 to your computer and use it in GitHub Desktop.
Save regiellis/7406d62ac47b6e9926b3231d34d0a553 to your computer and use it in GitHub Desktop.
ComfyUI hot-reload for custom nodes development
@echo off
setlocal enabledelayedexpansion
rem Get the main directory
set "SCRIPT_DIR=%~dp0"
rem Set paths relative
set "WATCH_DIR=%SCRIPT_DIR%ComfyUI\custom_nodes"
set "RUN_COMFY_SCRIPT=%SCRIPT_DIR%comfyui_manager.bat"
set "PID_FILE=%SCRIPT_DIR%comfyui.pid"
set "LOG_FILE=%SCRIPT_DIR%comfyui.log"
set "DEBOUNCE_SECONDS=5"
rem Define colors
set "GREEN=[92m"
set "RED=[91m"
set "YELLOW=[93m"
set "NC=[0m"
:is_comfyui_running
if exist "%PID_FILE%" (
for /f %%i in (%PID_FILE%) do (
tasklist /FI "PID eq %%i" 2>NUL | find /I /N "%%i">NUL
if !errorlevel! equ 0 exit /b 0
)
)
exit /b 1
:start_comfyui
echo %GREEN%Starting ComfyUI...%NC%
call "%RUN_COMFY_SCRIPT%" background
timeout /t 2 >nul
exit /b
:stop_comfyui
call :is_comfyui_running
if !errorlevel! equ 0 (
echo %YELLOW%Stopping ComfyUI...%NC%
call "%RUN_COMFY_SCRIPT%" stop
timeout /t 2 >nul
)
exit /b
:restart_comfyui
call :stop_comfyui
call :start_comfyui
exit /b
:watch_for_changes
set "last_restart=%time%"
:watch_loop
for /f "delims=" %%a in ('dir /s /b /a-d "%WATCH_DIR%\*.py" "%WATCH_DIR%\*.js" "%WATCH_DIR%\*.css"') do (
set "file_time=%%~ta"
call :check_file_time "!file_time!" "!last_restart!"
if !errorlevel! equ 1 (
echo %YELLOW%Changes detected. Restarting ComfyUI...%NC%
call :restart_comfyui
set "last_restart=%time%"
)
)
timeout /t 1 >nul
goto :watch_loop
:check_file_time
set "file_time=%~1"
set "last_restart=%~2"
powershell -Command "&{$ft=[datetime]::ParseExact('%file_time%','MM/dd/yyyy HH:mm:ss',$null);$lr=[datetime]::ParseExact('%last_restart%','HH:mm:ss.ff',$null);if(($ft - $lr).TotalSeconds -ge %DEBOUNCE_SECONDS%) {exit 1} else {exit 0}}"
exit /b
rem Start ComfyUI if it's not already running
call :is_comfyui_running
if !errorlevel! neq 0 call :start_comfyui
echo %GREEN%Watching %WATCH_DIR% for changes...%NC%
call :watch_for_changes
# Get the main directory
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
# Set paths relative
$WatchDir = Join-Path $ScriptDir "ComfyUI\custom_nodes"
$RunComfyScript = Join-Path $ScriptDir "comfyui_manager.ps1"
$PidFile = Join-Path $ScriptDir "comfyui.pid"
$LogFile = Join-Path $ScriptDir "comfyui.log"
$DebounceSeconds = 5
# Define colors
$Green = [System.ConsoleColor]::Green
$Red = [System.ConsoleColor]::Red
$Yellow = [System.ConsoleColor]::Yellow
function Is-ComfyUIRunning {
if (Test-Path $PidFile) {
$pid = Get-Content $PidFile
return Get-Process -Id $pid -ErrorAction SilentlyContinue
}
return $false
}
function Start-ComfyUI {
Write-Host "Starting ComfyUI..." -ForegroundColor $Green
& $RunComfyScript background
Start-Sleep -Seconds 2
}
function Stop-ComfyUI {
if (Is-ComfyUIRunning) {
Write-Host "Stopping ComfyUI..." -ForegroundColor $Yellow
& $RunComfyScript stop
Start-Sleep -Seconds 2
}
}
function Restart-ComfyUI {
Stop-ComfyUI
Start-ComfyUI
}
function Watch-ForChanges {
$lastRestart = Get-Date
while ($true) {
$changedFiles = Get-ChildItem -Path $WatchDir -Recurse -Include *.py,*.js,*.css |
Where-Object { $_.LastWriteTime -gt $lastRestart.AddSeconds(-$DebounceSeconds) }
if ($changedFiles) {
$currentTime = Get-Date
if (($currentTime - $lastRestart).TotalSeconds -ge $DebounceSeconds) {
Write-Host "Changes detected. Restarting ComfyUI..." -ForegroundColor $Yellow
Restart-ComfyUI
$lastRestart = $currentTime
}
}
Start-Sleep -Seconds 1
}
}
# Start ComfyUI if it's not already running
if (-not (Is-ComfyUIRunning)) {
Start-ComfyUI
}
Write-Host "Watching $WatchDir for changes..." -ForegroundColor $Green
Watch-ForChanges
#!/bin/bash
# Get the main directory
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
# Set paths relative
WATCH_DIR="$SCRIPT_DIR/ComfyUI/custom_nodes/"
RUN_COMFY_SCRIPT="$SCRIPT_DIR/run_comfy.sh" # custom bootstrap or use comfyui cli
PID_FILE="$SCRIPT_DIR/comfyui.pid"
LOG_FILE="$SCRIPT_DIR/comfyui.log"
DEBOUNCE_SECONDS=5
# Define colors
GREEN='\033[0;32m' # Green for success messages
RED='\033[0;31m' # Red for error messages
YELLOW='\033[0;33m' # Yellow for warnings
NC='\033[0m' # No Color
is_comfyui_running() {
[[ -f "$PID_FILE" ]] && kill -0 $(cat "$PID_FILE") 2>/dev/null
}
start_comfyui() {
echo -e "${GREEN}Starting ComfyUI...${NC}"
"$RUN_COMFY_SCRIPT" background
sleep 2 # Give it a moment to start
}
stop_comfyui() {
if is_comfyui_running; then
echo -e "${YELLOW}Stopping ComfyUI...${NC}"
"$RUN_COMFY_SCRIPT" stop
sleep 2 # Give it a moment to stop
fi
}
restart_comfyui() {
stop_comfyui
start_comfyui
}
watch_for_changes() {
local last_restart=$(date +%s)
while true; do
if find "$WATCH_DIR" -type f \( -name "*.py" -o -name "*.js" -o -name "*.css" \) -newermt "-${DEBOUNCE_SECONDS} seconds" | grep -q .; then
current_time=$(date +%s)
if ((current_time - last_restart >= DEBOUNCE_SECONDS)); then
echo -e "${YELLOW}Changes detected. Restarting ComfyUI...${NC}"
restart_comfyui
last_restart=$current_time
fi
fi
sleep 1
done
}
# Start ComfyUI if it's not already running
if ! is_comfyui_running; then
start_comfyui
fi
echo -e "${GREEN}Watching $WATCH_DIR for changes...${NC}"
watch_for_changes
@echo off
setlocal enabledelayedexpansion
set "SCRIPT_DIR=%~dp0"
set "COMFY_DIR=%SCRIPT_DIR%ComfyUI"
set "VENV_PATH=%COMFY_DIR%\.venv"
set "PID_FILE=%SCRIPT_DIR%comfyui.pid"
set "LOG_FILE=%SCRIPT_DIR%comfyui.log"
set "MAX_WAIT_TIME=60"
if "%1"=="" goto :usage
if "%1"=="start" goto :start_foreground
if "%1"=="background" goto :start_background
if "%1"=="stop" goto :stop
if "%1"=="restart" goto :restart
goto :usage
:start_background
echo Starting ComfyUI in the background...
call "%VENV_PATH%\Scripts\activate.bat"
start /B "" python -s "%COMFY_DIR%\main.py" --listen --preview-method auto > "%LOG_FILE%" 2>&1
for /f "tokens=2" %%i in ('tasklist /fi "imagename eq python.exe" /fo list /v ^| find /i "PID:"') do (
echo %%i > "%PID_FILE%"
echo ComfyUI started in background. PID: %%i
)
call :wait_for_comfyui_ready
goto :eof
:start_foreground
echo Starting ComfyUI in the foreground...
call "%VENV_PATH%\Scripts\activate.bat"
python -s "%COMFY_DIR%\main.py" --listen --preview-method auto
goto :eof
:stop
if exist "%PID_FILE%" (
set /p PID=<"%PID_FILE%"
echo Stopping ComfyUI (PID: !PID!)...
taskkill /F /PID !PID!
call :wait_for_comfyui_stop
del "%PID_FILE%"
echo ComfyUI stopped.
) else (
echo ComfyUI is not running in the background.
)
goto :eof
:wait_for_comfyui_ready
echo Waiting for ComfyUI to be fully operational...
set start_time=%time%
:wait_loop_ready
findstr /C:"Starting server" "%LOG_FILE%" >nul
if %errorlevel% equ 0 (
echo ComfyUI is now fully operational.
goto :eof
)
call :check_timeout
if %errorlevel% equ 1 goto :eof
timeout /t 1 /nobreak >nul
goto wait_loop_ready
:wait_for_comfyui_stop
echo Waiting for ComfyUI to stop...
set start_time=%time%
:wait_loop_stop
tasklist /FI "PID eq %PID%" 2>NUL | find /I /N "%PID%">NUL
if %errorlevel% neq 0 goto :eof
call :check_timeout
if %errorlevel% equ 1 (
echo Timeout: ComfyUI did not stop within %MAX_WAIT_TIME% seconds. Forcing stop.
taskkill /F /PID %PID%
goto :eof
)
timeout /t 1 /nobreak >nul
goto wait_loop_stop
:check_timeout
set end_time=%time%
set options="tokens=1-4 delims=:.,"
for /f %options% %%a in ("%start_time%") do set start_s=%%a&set start_m=%%b&set start_c=%%c
for /f %options% %%a in ("%end_time%") do set end_s=%%a&set end_m=%%b&set end_c=%%c
set /a start=(((start_s*60)+start_m)*60)+start_c
set /a end=(((end_s*60)+end_m)*60)+end_c
set /a elapsed=end-start
if %elapsed% geq %MAX_WAIT_TIME% (
echo Timeout: Operation did not complete within %MAX_WAIT_TIME% seconds.
exit /b 1
)
exit /b 0
:restart
call :stop
call :start_background
goto :eof
:usage
echo Usage: %~nx0 {start^|background^|stop^|restart}
exit /b 1
:eof
endlocal
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ComfyDir = Join-Path $ScriptDir "ComfyUI"
$VenvPath = Join-Path $ComfyDir ".venv"
$PidFile = Join-Path $ScriptDir "comfyui.pid"
$LogFile = Join-Path $ScriptDir "comfyui.log"
$MaxWaitTime = 60 # Maximum wait time in seconds
function Start-Background {
Write-Host "Starting ComfyUI in the background..."
$env:VIRTUAL_ENV = $VenvPath
$env:PATH = "$VenvPath\Scripts;$env:PATH"
$process = Start-Process -FilePath "python" -ArgumentList "-s", "$ComfyDir\main.py", "--listen", "--preview-method", "auto" -RedirectStandardOutput $LogFile -RedirectStandardError $LogFile -PassThru -NoNewWindow
$process.Id | Out-File -FilePath $PidFile
Write-Host "ComfyUI started in background. PID: $($process.Id)"
Wait-ForComfyUIReady
}
function Start-Foreground {
Write-Host "Starting ComfyUI in the foreground..."
$env:VIRTUAL_ENV = $VenvPath
$env:PATH = "$VenvPath\Scripts;$env:PATH"
& python -s "$ComfyDir\main.py" --listen --preview-method auto
}
function Stop-ComfyUI {
if (Test-Path $PidFile) {
$ComfyPID = Get-Content $PidFile
Write-Host "Stopping ComfyUI (PID: $ComfyPID)..."
Stop-Process -Id $ComfyPID -Force
Wait-ForComfyUIStop $ComfyPID
Remove-Item $PidFile
Write-Host "ComfyUI stopped."
} else {
Write-Host "ComfyUI is not running in the background."
}
}
function Wait-ForComfyUIReady {
Write-Host "Waiting for ComfyUI to be fully operational..."
$startTime = Get-Date
while ($true) {
if (Select-String -Path $LogFile -Pattern "Starting server" -Quiet) {
Write-Host "ComfyUI is now fully operational."
return
}
$elapsedTime = (Get-Date) - $startTime
if ($elapsedTime.TotalSeconds -ge $MaxWaitTime) {
Write-Host "Timeout: ComfyUI did not start within $MaxWaitTime seconds."
return
}
Start-Sleep -Seconds 1
}
}
function Wait-ForComfyUIStop {
param($ComfyPID)
Write-Host "Waiting for ComfyUI to stop..."
$startTime = Get-Date
while (Get-Process -Id $ComfyPID -ErrorAction SilentlyContinue) {
$elapsedTime = (Get-Date) - $startTime
if ($elapsedTime.TotalSeconds -ge $MaxWaitTime) {
Write-Host "Timeout: ComfyUI did not stop within $MaxWaitTime seconds. Forcing stop."
Stop-Process -Id $ComfyPID -Force
break
}
Start-Sleep -Seconds 1
}
}
switch ($args[0]) {
"start" { Start-Foreground }
"background" { Start-Background }
"stop" { Stop-ComfyUI }
"restart" {
Stop-ComfyUI
Start-Background
}
default {
Write-Host "Usage: $($MyInvocation.MyCommand.Name) {start|background|stop|restart}"
exit 1
}
}
#!/usr/bin/env zsh
SCRIPT_DIR="${0:A:h}"
COMFY_DIR="$SCRIPT_DIR/ComfyUI"
VENV_PATH="$COMFY_DIR/.venv"
PID_FILE="$SCRIPT_DIR/comfyui.pid"
LOG_FILE="$SCRIPT_DIR/comfyui.log"
MAX_WAIT_TIME=60 # Maximum wait time in seconds
start_background() {
echo "Starting ComfyUI in the background..."
source "$VENV_PATH/bin/activate"
nohup python -s "$COMFY_DIR/main.py" --listen --preview-method auto > "$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
echo "ComfyUI started in background. PID: $(cat "$PID_FILE")"
wait_for_comfyui_ready
}
start_foreground() {
echo "Starting ComfyUI in the foreground..."
source "$VENV_PATH/bin/activate"
python -s "$COMFY_DIR/main.py" --listen --preview-method auto
}
stop() {
if [[ -f "$PID_FILE" ]]; then
PID=$(cat "$PID_FILE")
echo "Stopping ComfyUI (PID: $PID)..."
kill "$PID"
wait_for_comfyui_stop
rm "$PID_FILE"
echo "ComfyUI stopped."
else
echo "ComfyUI is not running in the background."
fi
}
wait_for_comfyui_ready() {
echo "Waiting for ComfyUI to be fully operational..."
local start_time=$(date +%s)
while true; do
if grep -q "Starting server" "$LOG_FILE"; then
echo "ComfyUI is now fully operational."
return 0
fi
local current_time=$(date +%s)
local elapsed_time=$((current_time - start_time))
if [[ $elapsed_time -ge $MAX_WAIT_TIME ]]; then
echo "Timeout: ComfyUI did not start within $MAX_WAIT_TIME seconds."
return 1
fi
sleep 1
done
}
wait_for_comfyui_stop() {
echo "Waiting for ComfyUI to stop..."
local start_time=$(date +%s)
while kill -0 "$PID" 2>/dev/null; do
local current_time=$(date +%s)
local elapsed_time=$((current_time - start_time))
if [[ $elapsed_time -ge $MAX_WAIT_TIME ]]; then
echo "Timeout: ComfyUI did not stop within $MAX_WAIT_TIME seconds. Forcing stop."
kill -9 "$PID"
break
fi
sleep 1
done
}
case "$1" in
start)
start_foreground
;;
background)
start_background
;;
stop)
stop
;;
restart)
stop
start_background
;;
*)
echo "Usage: $0 {start|background|stop|restart}"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment