Chromium process architecture — why Puppeteer on a production server is challenging
Running headless Chromium on a production server is fundamentally different from local development. On your local machine, you have a GPU, plenty of RAM, and a single instance. On a VPS (especially with systemd and LXC), each of these resources is constrained, and you also face issues with user profiles, locked WebSocket connections, and orphaned processes.
Chromium uses a user-data-dir to store the browser profile state between sessions. When you launch two instances with the same profile, the second one gets a "profile still locked" error. The fix is giving each probe its own temporary directory.
The second challenge is Puppeteer communication. It normally uses WebSocket for remote debugging, but Puppeteer has a hardcoded 30-second timeout on WebSocket endpoint discovery — enough to kill a job in systemd/LXC environments. Switching to --remote-debugging-pipe bypasses this by using pipes instead of sockets.
The third problem is orphaned Chrome processes. When a job exceeds its timeout or is interrupted, the Chromium process isn't properly terminated and stays in memory as a zombie. Cyberapis v0.11.0 introduces orphan cleanup after each probe and a global lock preventing concurrent multi-instance launches.
New Features
Deploy SSH — automated deployments to Mikrus VPS
config/deploy-credentials.local.example (gitignored), scripts/mikrus-ssh.sh for SSH/SCP via Mikrus port 10173. Documentation in docs/DEPLOY_SSH.md and config/ssh-config.snippet for ~/.ssh/config.
Render probe queue batching
Instead of sequential runAll(), each monitoring gets its own RunRenderProbeForMonitoring job in a Laravel batch. This eliminates worker TimeoutExceededException with multiple sites and enables parallel processing.
Per-probe Browsershot configuration
Environment variables for Chromium control: BROWSERSHOT_PROBE_WAIT_UNTIL (default domcontentloaded), BROWSERSHOT_PROBE_TIMEOUT (60s), BROWSERSHOT_PROBE_PROTOCOL_TIMEOUT (120s), BROWSERSHOT_PROBE_PIPE (default true), BROWSERSHOT_PROBE_BLOCK_HEAVY, BROWSERSHOT_PROBE_PROFILES_DIR.
Detailed render probe failure logs
Logs for Monitoring render probe failed now include wait_until, timeouts, pipe, and stderr_tail — dramatically speeding up production diagnostics.
Bug Fixes
Separate user-data-dir for evaluation and screenshot
Style evaluate() and the failure screenshot now use separate Chromium profile directories, eliminating conflicts between operations in the same session.
Production paths for profiles and screenshots
Default /tmp paths worked for root but not for the queue worker running as cyberapis. Profiles and screenshots now go to storage/app/browsershot-profiles and storage/app/temp/render-probe-screenshots — directories with appropriate permissions.
Pipe transport instead of WebSocket
--remote-debugging-pipe bypasses Puppeteer's hardcoded 30-second WebSocket timeout, resolving job hangs in systemd/LXC environments.
Orphaned Chrome process cleanup
After each probe, the system terminates leftover Chrome processes, solving cascading "profile still locked" errors after timeouts.
Changes & Improvements
deploy.sh.example — queue restart after deploy
The deploy script now runs php artisan queue:restart after cache rebuild, forcing queue:work workers to reload PHP code (required with systemd on Mikrus).