Pārlūkot izejas kodu

CHECK_TIMEOUT and retry

ithewei 2 gadi atpakaļ
vecāks
revīzija
5906def1a6
2 mainītis faili ar 52 papildinājumiem un 29 dzēšanām
  1. 2 2
      http/HttpMessage.h
  2. 50 27
      http/client/HttpClient.cpp

+ 2 - 2
http/HttpMessage.h

@@ -391,8 +391,8 @@ public:
     // for HttpClient
     // for HttpClient
     uint16_t            timeout;        // unit: s
     uint16_t            timeout;        // unit: s
     uint16_t            connect_timeout;// unit: s
     uint16_t            connect_timeout;// unit: s
-    uint32_t            retry_count;    // just for AsyncHttpClient fail retry
-    uint32_t            retry_delay;    // just for AsyncHttpClient fail retry
+    uint32_t            retry_count;
+    uint32_t            retry_delay;    // unit: ms
     unsigned            redirect: 1;
     unsigned            redirect: 1;
     unsigned            proxy   : 1;
     unsigned            proxy   : 1;
 
 

+ 50 - 27
http/client/HttpClient.cpp

@@ -8,6 +8,7 @@
 
 
 #include "herr.h"
 #include "herr.h"
 #include "hlog.h"
 #include "hlog.h"
+#include "htime.h"
 #include "hstring.h"
 #include "hstring.h"
 #include "hsocket.h"
 #include "hsocket.h"
 #include "hssl.h"
 #include "hssl.h"
@@ -38,6 +39,7 @@ struct http_client_s {
 #endif
 #endif
     // for sync
     // for sync
     int             fd;
     int             fd;
+    unsigned int    keepalive_requests;
     hssl_t          ssl;
     hssl_t          ssl;
     hssl_ctx_t      ssl_ctx;
     hssl_ctx_t      ssl_ctx;
     bool            alloced_ssl_ctx;
     bool            alloced_ssl_ctx;
@@ -57,6 +59,7 @@ struct http_client_s {
         curl = NULL;
         curl = NULL;
 #endif
 #endif
         fd = -1;
         fd = -1;
+        keepalive_requests = 0;
         ssl = NULL;
         ssl = NULL;
         ssl_ctx = NULL;
         ssl_ctx = NULL;
         alloced_ssl_ctx = false;
         alloced_ssl_ctx = false;
@@ -249,6 +252,7 @@ int http_client_connect(http_client_t* cli, const char* host, int port, int http
     }
     }
 
 
     cli->fd = connfd;
     cli->fd = connfd;
+    cli->keepalive_requests = 0;
     return connfd;
     return connfd;
 }
 }
 
 
@@ -281,20 +285,30 @@ int http_client_recv_data(http_client_t* cli, char* data, int size) {
 static int http_client_exec(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
 static int http_client_exec(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
     // connect -> send -> recv -> http_parser
     // connect -> send -> recv -> http_parser
     int err = 0;
     int err = 0;
-    int timeout = req->timeout;
     int connfd = cli->fd;
     int connfd = cli->fd;
     bool https = req->IsHttps() && !req->IsProxy();
     bool https = req->IsHttps() && !req->IsProxy();
     bool keepalive = true;
     bool keepalive = true;
 
 
-    time_t start_time = time(NULL);
-    time_t cur_time;
-    int fail_cnt = 0;
-    if (connfd <= 0) {
-connect:
-        connfd = http_client_connect(cli, req->host.c_str(), req->port, https, MIN(req->connect_timeout, req->timeout));
-        if (connfd < 0) {
-            return connfd;
-        }
+    time_t connect_timeout = MIN(req->connect_timeout, req->timeout);
+    time_t timeout_ms = req->timeout * 1000;
+    time_t start_time = gettick_ms();
+    time_t cur_time = start_time, left_time = INFINITE;
+
+#define CHECK_TIMEOUT                                           \
+    do {                                                        \
+        if (timeout_ms > 0) {                                   \
+            cur_time = gettick_ms();                            \
+            if (cur_time - start_time >= timeout_ms) {          \
+                goto timeout;                                   \
+            }                                                   \
+            left_time = timeout_ms - (cur_time - start_time);   \
+        }                                                       \
+    } while(0);
+
+    uint32_t retry_count = req->retry_count;
+    if (cli->keepalive_requests > 0 && retry_count == 0) {
+        // maybe keep-alive timeout, retry at least once
+        retry_count = 1;
     }
     }
 
 
     if (cli->parser == NULL) {
     if (cli->parser == NULL) {
@@ -304,6 +318,15 @@ connect:
             return ERR_NULL_POINTER;
             return ERR_NULL_POINTER;
         }
         }
     }
     }
+
+    if (connfd <= 0) {
+connect:
+        connfd = http_client_connect(cli, req->host.c_str(), req->port, https, connect_timeout);
+        if (connfd < 0) {
+            return connfd;
+        }
+    }
+
     cli->parser->SubmitRequest(req);
     cli->parser->SubmitRequest(req);
     char recvbuf[1024] = {0};
     char recvbuf[1024] = {0};
     int total_nsend, nsend, nrecv;
     int total_nsend, nsend, nrecv;
@@ -314,21 +337,19 @@ send:
     while (cli->parser->GetSendData(&data, &len)) {
     while (cli->parser->GetSendData(&data, &len)) {
         total_nsend = 0;
         total_nsend = 0;
         while (total_nsend < len) {
         while (total_nsend < len) {
-            if (timeout > 0) {
-                cur_time = time(NULL);
-                if (cur_time - start_time >= timeout) {
-                    return ERR_TASK_TIMEOUT;
-                }
-                so_sndtimeo(cli->fd, (timeout-(cur_time-start_time)) * 1000);
+            CHECK_TIMEOUT
+            if (left_time != INFINITE) {
+                so_sndtimeo(cli->fd, left_time);
             }
             }
             nsend = http_client_send_data(cli, data + total_nsend, len - total_nsend);
             nsend = http_client_send_data(cli, data + total_nsend, len - total_nsend);
             if (nsend <= 0) {
             if (nsend <= 0) {
+                CHECK_TIMEOUT
                 err = socket_errno();
                 err = socket_errno();
                 if (err == EINTR) continue;
                 if (err == EINTR) continue;
-                if (++fail_cnt == 1) {
-                    // maybe keep-alive timeout, try again
+                if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
                     cli->Close();
                     cli->Close();
                     err = 0;
                     err = 0;
+                    if (req->retry_delay > 0) hv_msleep(req->retry_delay);
                     goto connect;
                     goto connect;
                 }
                 }
                 goto disconnect;
                 goto disconnect;
@@ -340,25 +361,23 @@ send:
     cli->parser->InitResponse(resp);
     cli->parser->InitResponse(resp);
 recv:
 recv:
     do {
     do {
-        if (timeout > 0) {
-            cur_time = time(NULL);
-            if (cur_time - start_time >= timeout) {
-                return ERR_TASK_TIMEOUT;
-            }
-            so_rcvtimeo(cli->fd, (timeout-(cur_time-start_time)) * 1000);
+        CHECK_TIMEOUT
+        if (left_time != INFINITE) {
+            so_rcvtimeo(cli->fd, left_time);
         }
         }
         nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
         nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
         if (nrecv <= 0) {
         if (nrecv <= 0) {
+            CHECK_TIMEOUT
             err = socket_errno();
             err = socket_errno();
             if (err == EINTR) continue;
             if (err == EINTR) continue;
             if (cli->parser->IsEof()) {
             if (cli->parser->IsEof()) {
                 err = 0;
                 err = 0;
                 goto disconnect;
                 goto disconnect;
             }
             }
-            if (++fail_cnt == 1) {
-                // maybe keep-alive timeout, try again
+            if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
                 cli->Close();
                 cli->Close();
                 err = 0;
                 err = 0;
+                if (req->retry_delay > 0) hv_msleep(req->retry_delay);
                 goto connect;
                 goto connect;
             }
             }
             goto disconnect;
             goto disconnect;
@@ -370,10 +389,14 @@ recv:
     } while(!cli->parser->IsComplete());
     } while(!cli->parser->IsComplete());
 
 
     keepalive = req->IsKeepAlive() && resp->IsKeepAlive();
     keepalive = req->IsKeepAlive() && resp->IsKeepAlive();
-    if (!keepalive) {
+    if (keepalive) {
+        ++cli->keepalive_requests;
+    } else {
         cli->Close();
         cli->Close();
     }
     }
     return 0;
     return 0;
+timeout:
+    err = ERR_TASK_TIMEOUT;
 disconnect:
 disconnect:
     cli->Close();
     cli->Close();
     return err;
     return err;