
데이터 전송을 시작하는 데 꽤 오랜 시간이 걸리는 다소 리소스 집약적인 CGI가 있습니다. 우리는 참을성 없는 사람들이 몇 번 다시 로드한 다음 CGI의 추가 실행을 트리거하거나 클라이언트가 시간 초과되어 연결을 끊었지만 CGI는 계속 실행되는 경우를 꽤 많이 보았습니다.
이런 일이 발생했을 때 감지할 수 있는 좋은 방법이 있습니까? CGI 자체 내에 있을 필요도 없지만(그렇지 않으면 더 좋을 것입니다. 내가 제어할 수 없는 다른 프로그램에 넘겨줍니다), 자주 실행되는 크론 작업일 수도 있습니다. 수확할 죽은 연결을 찾는 것입니다.
저는 현재 Apache를 사용하고 있지만, 이 문제를 처리할 수 있는 조항(또는 문제를 모니터링할 수 있는 방법)이 있는 경우 다른 웹 서버를 기꺼이 실행할 의향이 있는 문제입니다.
답변1
일반적으로 사용자에게 다시 쓰기를 시작할 때까지는 끊어진 연결을 감지할 수 없습니다. 그렇지 않으면 프로세스가 사용자 측에서 연결 중단을 인지하지 못한 채 작업을 계속 수행하게 됩니다.이 게시물PHP에 대해 이야기하더라도 관련이 있습니다. 개념은 동일해야합니다.
시도해 볼 수 있는 작업은 다음과 같습니다.
- 시간이 많이 걸리는 작업을 백그라운드에서 수행합니다. 사용자가 CGI를 요청할 때 작업을 일반 차단 호출로 실행하지 마세요. 요청이 처리 중임을 알리기 위해 사용자에게 무엇이든 반환하면 됩니다. 물론 일부 요청 ID나 IP를 사용하여 작업 상태를 확인하려면 보기를 업데이트하거나 다른 페이지를 제공하는 방법을 찾아야 합니다.
- 가능한 한 빨리 데이터를 클라이언트에 다시 보내고 전송에 실패하면 종료합니다(연결이 끊어졌음을 나타냄). 예를 들어 몇 초 또는 몇 분마다 작업 진행 상황을 보낼 수 있습니다.
현재 실행 중인 작업을 데이터베이스에 저장하면 요청 ID 및/또는 클라이언트 IP 주소를 저장할 수 있습니다. 따라서 사용자에게 "요청이 처리 중입니다"라고 알리는 동일한 리소스에 대한 중복 요청을 감지하고 무시할 수 있습니다.
답변2
경고: 이 정보는 더 이상 사용되지 않을 수 있습니다. 마지막 단락을 참조하세요.
같은 문제가 있어서 해결했던 기억이 나네요.nph(파싱 헤더 없음) CGI 스크립트.
일반적으로 Apache는 스크립트에서 모든 헤더를 수집하고 헤더 읽기가 끝나면 제공하지 않은 일부 표준 헤더로 수정합니다. 이는 또한 헤더를 완료하지 않는 한 Apache가 클라이언트에 아무것도 보내지 않는다는 것을 의미합니다.
nph 스크립트를 사용하면 모든 헤더를 제공해야 하지만 Apache는 이를 클라이언트에 즉시 보내고 클라이언트 연결이 끊어지면 CGI 스크립트에 SIGPIPE를 보냅니다. 따라서 X-Slowly-Counting-Part-nnn: yes
클라이언트의 시간 초과를 방지하기 위해 몇 초마다 헤더를 보낼 수 있으며 , 클라이언트가 연결을 끊으면 알림을 받게 됩니다.
여전히 HTTP 상태를 먼저 보내야 하는 문제가 남아 있지만 'Content-Length: 0' 또는 'Content-Length: 1'을 보내고 콘텐츠를 보내지 않고 연결을 닫으면 파일이 다운로더~해야 한다네트워크 오류를 가정하고 그에 따라 행동하십시오.
프로세스를 통해 다른 프로그램의 출력을 파이프해야 할 수도 있지만 적어도 Linux에서 시스템 sendfile(2)
호출을 사용하는 경우 이는 큰 성능 저하가 되어서는 안 됩니다.
이 모든 것의 문제는 내가 적어도 10년 전에 아마도 Apache 1.3에서 그것을 사용했고 인터넷 검색으로 apache cgi nph
유용한 결과를 얻지 못했다는 것입니다. 그래서 그 사이에 nph 기능이 제거되었을 수도 있습니다. 하지만 그렇지 않았을 수도 있습니다. 제가 그다지 열심히 보지 않았다는 것을 인정합니다.
답변3
오래된 질문이지만 동일한 문제가 있었고 연결이 안정적인지 확인하여 해결했습니다.
제 경우에는 서버에서 하나의 bash 스크립팅을 실행하고 있습니다. env 변수는 mod_cgi에 의해 내보내집니다. 이 솔루션은 CGI에서 실행되는 모든 프로그램/스크립트에서 작동할 것이라고 믿습니다.
ss -nt state established "( sport = :$SERVER_PORT and dport = $REMOTE_ADDR:$REMOTE_PORT )" 2>/dev/null | grep -q "$REMOTE_ADDR:$REMOTE_PORT"
if [ "$?" -ne '0' ]; then
# Client closed browser/connection
fi