watchdog 타이머를 사용하여 정상적인 Node.js 프로그램 보장
14498 단어 node
그러한 프로그램이 어떻게 보일 수 있는지에 대한 예를 고려하십시오.
import delay from 'delay';
const getNextJob = async () => { /* ... */ };
const doJob = async () => { /* ... */ };
const main = async () => {
while (true) {
const maybeNextJob = await getNextJob();
if (maybeNextJob) {
await doJob(maybeNextJob);
} else {
await delay(1000);
}
}
};
main();
getNextJob
는 임의의 데이터베이스에서 작업 명령을 가져오는 데 사용되며 doJob
는 이러한 작업을 실행하는 데 사용됩니다.여기서 위험은 모든 비동기 작업이 무기한 중단될 수 있다는 것입니다.
getNextJob
가 원격 데이터베이스에서 데이터를 가져오는 경우 데이터베이스 소켓이 무기한 중단될 수 있습니다. 이것은 거의 항상 버그입니다.내 특정 경우에는
node-postgres
에서 bug이 발생하여 ClientRead
상태에서 연결이 중단되었습니다. 후자는 서버가 쿼리를 시작하는 프로토콜 메시지를 보았지만 아직 유휴 상태로 돌아가지 않은 경우 발생합니다. 이는 서버가 쿼리 끝에 ReadyForQuery
응답을 보낼 때 발생합니다. PostgreSQL에는 ClientRead
에 대한 시간 초과가 없습니다.이러한 위험으로부터 보호하는 가장 좋은 방법은 작업을 가져오고 실행하는 데 사용되는 루프에 시간 초과를 추가하는 것입니다. 시간 초과는 모든 반복에서 새로 고쳐져야 합니다. 시간 초과가 제 시간에 재설정되지 않으면 프로세스를 종료하고 프로세스가 중단된 원인을 식별할 수 있도록 충분한 세부 정보를 기록해야 합니다. 이 패턴을 watchdog timer 이라고 합니다.
다음은 워치독 타이머의 구현 예입니다.
import delay from 'delay';
const getNextJob = async () => { /* ... */ };
const doJob = async () => { /* ... */ };
const main = async () => {
const timeoutId = setTimeout(() => {
console.error('watchdog timer timeout; forcing program termination');
process.exit(1);
}, 30 * 1000);
timeoutId.unref();
while (true) {
timeoutId.refresh();
const maybeNextJob = await getNextJob();
if (maybeNextJob) {
await doJob(maybeNextJob);
} else {
await delay(1000);
}
}
};
main();
이렇게 하면 새 작업을 확인하는 모든 루프가 시작될 때 새로 고쳐지는 타이머가 생성됩니다. 30초 시간 제한은 전체 주기(예:
getNextJob
및 getNextJob
)에 대한 것이며 갑작스러운 종료를 강제하기 때문에 내부 작업 제한보다 훨씬 높아야 합니다.Kubernetes를 사용하여 오케스트레이션된 많은 프로세스의 대규모 배포에서 이러한 고스트 프로세스가 중단되는 것을 방지하기 위해 여러 애플리케이션에서 위의 패턴을 구현해야 했습니다. 따라서 위의 논리 + 약간의 설탕을 모듈로 추상화했습니다watchdog-timer. 대부분의 경우
doJob
를 사용하여 이전 예제와 똑같이 사용할 수 있습니다.import {
createWatchdogTimer,
} from 'watchdog-timer';
import delay from 'delay';
const getNextJob = async () => { /* ... */ };
const doJob = async () => { /* ... */ };
const main = async () => {
const watchdogTimer = createWatchdogTimer({
onTimeout: () => {
console.error('watchdog timer timeout; forcing program termination');
process.exit(1);
},
timeout: 1000,
});
while (true) {
watchdogTimer.refresh();
const maybeNextJob = await getNextJob();
if (maybeNextJob) {
await doJob(maybeNextJob);
} else {
await delay(1000);
}
}
};
main();
이것이 진행 중인 가드라는 점을 강조하는 것이 중요합니다. 즉, 이벤트 루프를 차단하는 것이 있으면 타임아웃이 호출되지 않습니다. 후자로부터 자신을 보호하려면 애플리케이션의 활성 상태를 확인하는 외부 서비스도 필요합니다. Kubernetes를 사용하는 경우 이 기능은
setTimeout
에서 제공되며 livenessProbe
NPM 모듈을 사용하여 구현할 수 있습니다.lightship
Lightship과 잘 통합됩니다.import {
createWatchdogTimer,
} from 'watchdog-timer';
import {
createLightship,
} from 'lightship';
const main = async () => {
const lightship = createLightship({
timeout: 5 * 1000,
});
lightship.signalReady();
lightship.registerShutdownHandler(async () => {
console.log('shutting down');
});
const watchdogTimer = createWatchdogTimer({
onTimeout: () => {
// If you do not call `destroy()`, then
// `onTimeout` is going to be called again on the next timeout.
watchdogTimer.destroy();
lightship.shutdown();
},
timeout: 1000,
});
while (true) {
if (lightship.isServerShuttingDown()) {
console.log('detected that the service is shutting down; terminating the event loop');
break;
}
// Reset watchdog-timer on each loop.
watchdogTimer.reset();
// `foo` is an arbitrary routine that might hang indefinitely,
// e.g. due to a hanging database connection socket.
await foo();
}
watchdogTimer.destroy();
};
main();
요약하자면, 프로세스 중단을 방지하려면 애플리케이션이 유휴 상태로 있거나 예상 단계를 수행하지 않을 때를 찾기 위해 프로세스 내 감시 장치가 있어야 합니다. 애플리케이션이 차단 이벤트 루프에 걸리지 않도록 하려면 out-of-process watchdog을 사용해야 합니다.
Reference
이 문제에 관하여(watchdog 타이머를 사용하여 정상적인 Node.js 프로그램 보장), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/gajus/ensuring-healthy-node-js-program-using-watchdog-timer-4pjd텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)