2010-12-21 4 views
2

HTTP POST (사용자가 아닌 응용 프로그램에서 생성) 이후 전자 메일을 보내려고합니다. 전자 우편을받는 절차가 올바르지 만 Java 웹 응용 프로그램 서버가 어떻게 작동하는지 잘 모르겠습니다.doGet 또는 doPost에서 잠재적으로 긴 작업을 처리하는 방법은 무엇입니까?

나는 특히 타임 아웃이 걱정되며, 중요한 스레드를 어떻게 든 막는 지 알고 싶다.

나는 다음과 같은 일을하는 경우 :

@Override 
    public void doPost(
      final HttpServletRequest req, 
      final HttpServletResponse resp 
    ) throws IOException, ServletException { 
     final PrintWriter pw = resp.getWriter(); 
     pw.write(...); 
     pw.flush(); 
     pw.close(); 
     // Here I'm sending an email, this can potentially 
     // block until the email send procedure times out 
     // (the timeout is set to 5 seconds) 
     sendEmail(...); 
    } 

그리고 이메일 서버가 다운되면 내 sendEmail 시간 초과 (타임 아웃이 내가 몇 초로 설정하는) 때까지 스레드가 차단됩니다

.

어떤 스레드를 차단합니까? 내 말은, 분명히이 POST를 처리하고있는 스레드를 차단하고 있지만 이것이 문제라는 것을 알 수 있습니까? 이 스레드가 다음에해야 할 일은 무엇입니까?

나는 자바 웹 응용 프로그램 서버에서 새 스레드를 만들어서는 안된다는 것을 읽었으므로 다음과 같이해야하지 않겠습니까? 내 질문에 보내는 이메일을 특정하지

Thread t = new Thread(new Runnable() { 
     public void run() { 
      sendEmail(); 
     } 
    }); 
    t.start(); 

참고 : 나는 자바 웹 애플리케이션마다에서 알아서해야 이해하려는 당신은 GET 또는 이후에 잠재적으로 차단/긴 작업을 할 계획 게시하다.

답변

2

서블릿 내부에서 스레드를 시작하는 것이 좋지만 서블릿을 배포 해제 할 때 스레드가 죽는 것을주의 깊게 관찰하면됩니다.

서블릿이 시작될 때 java.util.concurrent.ExecutorService을 생성하는 가장 쉬운 방법은 서블릿이 삭제 될 때 해당 서블릿을 시작하고 종료하는 것입니다. 그런 다음 집행자 서비스에 이메일 작업을 제출하고 doPost에서 돌아올 수 있습니다. 작업이 대기열에 넣어 진 후에 서블릿이 파괴되면 일부 전자 메일이 보내지지 않을 수도 있습니다. 코드에서

:

class EmailServlet extends HttpServlet { 
    private ExecutorService emailSender; 

    public void init() { 
     emailSender = Executors.newFixedThreadPool(1); 
    } 

    public void destroy() { 
     emailSender.shutdownNow(); 
    } 

    public void doPost(...) { 
     ... 
     emailSender.execute(new Runnable() {public void run() {sendEmail();}}); 
    } 
} 
+0

서블릿은 언제 배포 해제됩니까? 예를 들어 .war을 배포 해제하고 재배포 할 때? 만약 내가 죽지 않는다면 Tomcat을 재시작하지 않고 Tomcat이 내 .war 파일을 배포 해제/재배포 할 때마다 더 이상 아무 것도하지 않는 스레드가 더 많이 생길 것입니다. (정확히 이해하고 있습니까?) – NoozNooz42

+0

컨테이너에 따라 다르지만 .war의 배포 해제 및 재배포는'destroy'를 호출해야합니다. 아마도 컨테이너에 의존하여 컨테이너를 올바르게 사용할 수 있습니다 (그러나 확실히하기 위해 일부 로그인하는 것은 아쉽지 않습니다). 하나의 서블릿 인스턴스에서'init'을 두 번 호출하면 서블릿 스펙을 충족시키지 못하기 때문에 매우 놀랍습니다. –

1

내 충고 :해야 할 작업 (즉, 데이터베이스 또는 대기열)을 두 번째 프로세스에서 백그라운드로 처리하고 가능한 한 빨리 반환하십시오 (doPost/doGet). 사용자는 기다리고 싶지 않습니다.

예를 들어, 외부 앱 요청을 받고, 데이터베이스에 보내거나 JMS 대기열에 넣을 이메일을 저장할 수 있습니다 (많은 애플리케이션 서버에는 JMS 기능이 있지만 사용하지는 않았습니다). 반환. 다른 프로세스는 해당 데이터베이스/큐를 읽고 HTTP 응답을 차단하지 않고 전자 메일을 보낼 수 있습니다.

웹 응용 프로그램에서 스레드를 사용하면 작동하며 가장 간단한 솔루션 일 수 있지만 확장 성 문제가있을 수 있습니다. 그렇게하면 웹 서버/운영 체제에 일반적으로 스레드 수에 제한이 있기 때문에 일종의 스레드 풀 (ExecutorService ...)을 사용해야합니다.

+0

예를 들어 나는 큐의 모든 게시물의 이메일 요청을 넣고 그 디큐 다른 (독특한) 스레드가 그들을 보낼 수 있습니다. 그러나 이것은 적어도 하나의 다른 스레드를 생성해야 함을 의미합니다. 그렇게해도 괜찮습니까? 내 경우에는 사용자가 아닌 POST를 수행하는 다른 응용 프로그램입니다. – NoozNooz42

+0

그러나 어쨌든, 사용자가 보낸 이러한 POST는 스트림을 닫는 즉시 페이지를 다시 가져 오는 사용자가 아닙니다. (전자 메일 보내기 전에 수행) – NoozNooz42

+0

예. 응용 프로그램이 응답을 되 돌리더라도 서버가 여전히 확장 성 문제에 직면 할 수 있습니다.아마도 서버 구성에 따라 다르지만 서버가 500 개의 동시 요청을 지원하도록 구성되어 있고 모두가 전자 메일을 보내고 있기 때문에 슬롯이 부족한 경우 어떻게 될지 상상해보십시오. –

관련 문제