()
| 735 | var prevMono = process.hrtime.bigint(); |
| 736 | var skippedLastTick = false; |
| 737 | var watchRun = function () { |
| 738 | try { |
| 739 | var nowWall = Date.now(); |
| 740 | var nowMono = process.hrtime.bigint(); |
| 741 | var wallDelta = nowWall - prevWall; |
| 742 | var monoDeltaMs = Number((nowMono - prevMono) / 1000000n); |
| 743 | // Wall-clock can jump forward after macOS sleep/resume; monotonic |
| 744 | // clock does not. If the gap exceeds 60s, skip the stagnation |
| 745 | // restart this tick to give the daemon a grace period — but only |
| 746 | // once in a row, so a genuinely stuck daemon still gets restarted. |
| 747 | var clockJumped = (wallDelta - monoDeltaMs) > 60000 && !skippedLastTick; |
| 748 | var wh = checkHealth(); |
| 749 | var ts = new Date().toISOString(); |
| 750 | if (wh.healthy) { |
| 751 | console.log('[Watch] ' + ts + ' healthy pids=' + (wh.pids || []).join(',')); |
| 752 | skippedLastTick = false; |
| 753 | } else if (clockJumped && wh.reason === 'stagnation') { |
| 754 | console.log('[watch] wall-clock jump detected (+' + Math.round((wallDelta - monoDeltaMs) / 1000) + 's), skipping stagnation check this cycle to give daemon a grace period'); |
| 755 | skippedLastTick = true; |
| 756 | } else { |
| 757 | console.log('[Watch] ' + ts + ' unhealthy reason=' + wh.reason + ' restarting...'); |
| 758 | var res = restart(); |
| 759 | console.log('[Watch] restart result: ' + JSON.stringify(res)); |
| 760 | skippedLastTick = false; |
| 761 | } |
| 762 | prevWall = nowWall; |
| 763 | prevMono = nowMono; |
| 764 | } catch (e) { |
| 765 | console.error('[watch] tick error: ' + (e && e.stack || e)); |
| 766 | } |
| 767 | }; |
| 768 | try { watchRun(); } catch (e) { console.error('[watch] tick error: ' + (e && e.stack || e)); } |
| 769 | if (!watchOnce) { |
| 770 | setInterval(function () { |
no test coverage detected