2017-10-19 189 views
4

我遇到一個奇怪的問題,其中org.apache.http.NoHttpResponseException作爲未經檢查的異常拋出,即使是已檢查的異常,因爲它延伸java.io.IOException ...從以下內容可以看出發佈stacktrace我收到一個異常,應該在編譯時檢查爲未經檢查的運行時異常。作爲運行時異常拋出的NoHttpResponseException即使是已檢查的異常

,我得到的是如下異常的堆棧跟蹤(我的課是在包:com.example.staticsite):

org.apache.http.NoHttpResponseException: sqs.eu-west-1.amazonaws.com failed to respond 
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:143) 
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57) 
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260) 
    at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:283) 
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:251) 
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:197) 
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:271) 
    at com.amazonaws.http.protocol.SdkHttpRequestExecutor.doReceiveResponse(SdkHttpRequestExecutor.java:66) 
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123) 
    at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:685) 
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:487) 
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863) 
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) 
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57) 
    at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:728) 
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:489) 
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:310) 
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2419) 
    at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1130) 
    at com.example.staticsite.aws.SqsReceiverImpl.receiveReceipt(SqsReceiverImpl.java:57) 
    at com.example.staticsite.core.processsite.ProcessSiteImpl.runOneTime(ProcessSiteImpl.java:59) 
    at com.example.staticsite.core.processsite.ProcessSiteImpl.run(ProcessSiteImpl.java:44) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622) 
    at java.lang.Thread.run(Thread.java:748) 

被扔我的代碼裏面異常的方法是:

public class SqsReceiverImpl implements SqsReceiver { 
    private AmazonSQS client; 
    private String queueUrl; 

    @Inject 
    public SqsReceiverImpl(AmazonSQS client,@Assisted String queueUrl) {   
     this.client = client; 
     this.queueUrl = queueUrl; 
    } 

    public List<String> receiveReceipt() throws SqsReceiverException { 
     if(queueUrl == null) 
      throw new SqsReceiverException(SqsReceiverException.MESSAGE_NO_QUEURURL); 
     ReceiveMessageRequest request = new ReceiveMessageRequest(); 
     request.setMaxNumberOfMessages(10); 
     request.setQueueUrl(queueUrl); 
     request.setWaitTimeSeconds(20); 

     ReceiveMessageResult results = null; 
     try { 
      results = client.receiveMessage(request); 
     } 
     catch(OverLimitException oe){ 
      throw new SqsReceiverException("OverLimitException thrown"); 
     } 
     catch(AmazonServiceException oe){ 
      throw new SqsReceiverException("AmazonServiceException thrown"); 
     } 
     catch(AmazonClientException oe){ 
      throw new SqsReceiverException("AmazonClientException thrown"); 
     } 

SqsReceiverException定義如下:

public class SqsReceiverException extends Exception{ 

    public SqsReceiverException(String messageNoQueururl) { 
     super(messageNoQueururl); 
    } 
    public static final String MESSAGE_NO_QUEURURL = "Queue url not found. Se the queue url"; 
} 

只POM的文件依賴條件的聲明如下:

<dependencies> 
     <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>4.11</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
    <groupId>log4j</groupId> 
    <artifactId>log4j</artifactId> 
    <version>1.2.17</version> 
</dependency> 
<dependency> 
    <groupId>com.amazonaws</groupId> 
    <artifactId>aws-java-sdk-sqs</artifactId> 
    <version>1.10.12</version> 
</dependency> 
<dependency> 
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-core</artifactId> 
    <version>1.10.19</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>com.google.inject</groupId> 
    <artifactId>guice</artifactId> 
    <version>4.0</version> 
</dependency> 
<dependency> 
    <groupId>com.google.inject.extensions</groupId> 
    <artifactId>guice-assistedinject</artifactId> 
    <version>4.0</version> 
</dependency> 
<dependency> 
    <groupId>org.apache.commons</groupId> 
    <artifactId>commons-lang3</artifactId> 
    <version>3.4</version> 
</dependency> 
</dependencies> 

生產這種結果:

Maven dependencies tree

怎麼可能,這個異常threated爲未選中,同時應檢查? 有什麼我在這裏失蹤?

異常並不總是重複性,因爲它只發生在生產時,有來自亞馬遜的服務缺失的響應。

更新

我驗證下來的堆棧跟蹤,直到到達AmazonHttpClient類,而有這個代碼是捕捉`IOException異常」:

catch (IOException ioe) { 
       if (log.isInfoEnabled()) { 
        log.info("Unable to execute HTTP request: " + ioe.getMessage(), ioe); 
       } 
       captureExceptionMetrics(ioe, awsRequestMetrics); 
       awsRequestMetrics.addProperty(AWSRequestID, null); 
       AmazonClientException ace = new AmazonClientException(
         "Unable to execute HTTP request: " + ioe.getMessage(), 
         ioe); 
       if (!shouldRetry(request.getOriginalRequest(), 
           p.apacheRequest, 
           ace, 
           p.requestCount, 
           config.getRetryPolicy())) { 
        throw lastReset(ace, request); 
       } 
       // Cache the retryable exception 
       p.retriedException = ace; 
      } 

而且lastReset應該是負責拋出的異常,我不明白的是如何記錄異常可能是org.apache.http.NoHttpResponseException ...

堆棧跟蹤之前的行總是s:

2017-09-15 07:41:39 INFO AmazonHttpClient:496 - Unable to execute HTTP request: sqs.eu-west-1.amazonaws.com failed to respond 
+0

您使用的是哪種AmazonSqs客戶端?異步版本? –

+0

奇怪的確是因爲異常類型也沒有改變,它確實只是一個IOException。這在客戶端運行到亞馬遜方? –

+0

它運行在亞馬遜EC2實例上,亞馬遜紅帽子linux AMI – aleroot

回答

2

我的猜測是你是堆棧跟蹤格式化的受害者。

我認爲你是對的,當你用手指lastReset()作爲罪魁禍首。這是您看到throws IOException從堆棧軌跡中消失的位置。這種方法顯然拋出了一個AmazonClientException(運行時異常),其中原始的NoHttpResponseException「內部」。

你可以像這樣用一個片段模擬這個:

throw new AmazonClientException("Oh no!", new NoHttpResponseException("The AWS server doesn't like you")); 

如果我插入這行代碼到現有的Java應用程序(春季啓動,在這種情況下),這是我在Eclipse中看到控制檯:

No sign of the runtime exception

AmazonClientException的標誌!直到,我向右滾動:

There it is

亞馬遜的決定去與unchecked異常,並documented it here

因此,他們確實(我敢肯定)將您的IOException包裝在運行時異常中,通過給予您「對您處理的錯誤的精細控制」來「幫助」您,儘管這並不總是很明顯。

所有這一切說,我可能是錯的。如果我是對的,我希望看到您的自定義SqsReceiverException位於堆棧頂部,因爲您確實抓到了AmazonClientException

在堆棧跟蹤之前很難確定沒有標準的最後幾行。如果我不符合標準,你可以發佈它們嗎?

更新

你更新了(AmazonHttpClient:496)問題上的線是打印棧跟蹤行。當您通過Throwablelog.info()時,將會打印堆棧跟蹤。此痕跡正在記錄之前您的異常被包裝並重新拋出。

因此,此位被看似「吞噬」:

com.amazonaws.AmazonClientException: Unable to execute HTTP request: sqs.us-east-1.amazonaws.com failed to respond 
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:500) 
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:310) 
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2419) 
    at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1130) 
    at httptest.Main.main(Main.java:32) 
Caused by: 

,我可以不丟失SqsReceiverException說話。但我不認爲DefaultRequestDirector.execute()的簽名是謊言,我不認爲我們正在處理編譯器錯誤。

也許您可以將oe.printStackTrace()添加到您的catch (AmazonClientException oe)區塊?

最後,我建議通過調試器來完成這一步。爲了模擬您的生產問題,只需在DefaultHttpResponseParser:140處設置一個斷點,在此行執行後,將i更改爲-1。然後將堆棧退回到您的代碼。

我還在AmazonHttpClient:971設置了一個斷點,所以我可以更改retries並避免四次循環。

+1

在最後使用始終在堆棧跟蹤之前的行更新了問題,在其之前或之後沒有其他相關行。我在日誌文件中根本沒有'SqsReceiverException'。這是最奇怪的事情。 – aleroot

+0

@aleroot感謝您更新問題。我相應地更新了我的答案。 –