diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index e428e7376..ca523f28d 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -69,6 +69,7 @@ struct ngx_peer_connection_s { unsigned transparent:1; unsigned so_keepalive:1; unsigned down:1; + unsigned unique:1; /* ngx_connection_log_error_e */ unsigned log_error:2; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 7e08df702..de65795b0 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -575,6 +575,20 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout), NULL }, + { ngx_string("proxy_next_upstream_delay"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_delay), + NULL }, + + { ngx_string("proxy_next_upstream_unique"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_unique), + NULL }, + { ngx_string("proxy_pass_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, @@ -3524,6 +3538,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.request_buffering = NGX_CONF_UNSET; conf->upstream.ignore_client_abort = NGX_CONF_UNSET; conf->upstream.force_ranges = NGX_CONF_UNSET; + conf->upstream.next_upstream_unique = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; conf->upstream.socket_keepalive = NGX_CONF_UNSET; @@ -3532,6 +3547,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.next_upstream_delay = NGX_CONF_UNSET_MSEC; conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; @@ -3656,6 +3672,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->upstream.force_ranges, prev->upstream.force_ranges, 0); + ngx_conf_merge_value(conf->upstream.next_upstream_unique, + prev->upstream.next_upstream_unique, 1); + ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); @@ -3674,6 +3693,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, prev->upstream.next_upstream_timeout, 0); + ngx_conf_merge_msec_value(conf->upstream.next_upstream_delay, + prev->upstream.next_upstream_delay, 0); + ngx_conf_merge_size_value(conf->upstream.send_lowat, prev->upstream.send_lowat, 0); diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c index 1835aee80..0d990ed34 100644 --- a/src/http/modules/ngx_http_upstream_hash_module.c +++ b/src/http/modules/ngx_http_upstream_hash_module.c @@ -308,7 +308,9 @@ found: ngx_http_upstream_rr_peer_unlock(hp->rrp.peers, peer); ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); - hp->rrp.tried[n] |= m; + if (pc->unique) { + hp->rrp.tried[n] |= m; + } return NGX_OK; } @@ -713,7 +715,9 @@ found: n = best_i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << best_i % (8 * sizeof(uintptr_t)); - hp->rrp.tried[n] |= m; + if (pc->unique) { + hp->rrp.tried[n] |= m; + } return NGX_OK; } diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c index 066f457d1..8625ca1d1 100644 --- a/src/http/modules/ngx_http_upstream_least_conn_module.c +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c @@ -271,7 +271,9 @@ best_chosen: n = p / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); - rrp->tried[n] |= m; + if (pc->unique) { + rrp->tried[n] |= m; + } ngx_http_upstream_rr_peers_unlock(peers); diff --git a/src/http/modules/ngx_http_upstream_random_module.c b/src/http/modules/ngx_http_upstream_random_module.c index 72885cde8..344ece333 100644 --- a/src/http/modules/ngx_http_upstream_random_module.c +++ b/src/http/modules/ngx_http_upstream_random_module.c @@ -327,7 +327,9 @@ found: ngx_http_upstream_rr_peer_unlock(peers, peer); ngx_http_upstream_rr_peers_unlock(peers); - rrp->tried[n] |= m; + if (pc->unique) { + rrp->tried[n] |= m; + } return NGX_OK; } @@ -463,7 +465,9 @@ found: ngx_http_upstream_rr_peers_unlock(peers); - rrp->tried[n] |= m; + if (pc->unique) { + rrp->tried[n] |= m; + } return NGX_OK; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index bd6ae5f07..88a18d00d 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -99,6 +99,7 @@ static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r, static void ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t ft_type); static void ngx_http_upstream_cleanup(void *data); +static void ngx_http_upstream_connect_handler(ngx_event_t *ev); static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc); @@ -844,9 +845,10 @@ found: } u->peer.start_time = ngx_current_msec; + u->peer.unique = u->conf->next_upstream_unique; if (u->conf->next_upstream_tries - && u->peer.tries > u->conf->next_upstream_tries) + && (!u->peer.unique || u->peer.tries > u->conf->next_upstream_tries)) { u->peer.tries = u->conf->next_upstream_tries; } @@ -1287,9 +1289,10 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) ur->ctx = NULL; u->peer.start_time = ngx_current_msec; + u->peer.unique = u->conf->next_upstream_unique; if (u->conf->next_upstream_tries - && u->peer.tries > u->conf->next_upstream_tries) + && (!u->peer.unique || u->peer.tries > u->conf->next_upstream_tries)) { u->peer.tries = u->conf->next_upstream_tries; } @@ -4743,6 +4746,42 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, u->peer.connection = NULL; } + if (u->conf->next_upstream_delay) { + + if (u->event == NULL) { + u->event = ngx_pcalloc(r->pool, sizeof(ngx_event_t)); + if (u->event == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->event->handler = ngx_http_upstream_connect_handler; + u->event->data = r; + u->event->log = r->connection->log; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "next http upstream delay %M", + u->conf->next_upstream_delay); + + ngx_add_timer(u->event, u->conf->next_upstream_delay); + return; + } + + ngx_http_upstream_connect(r, u); +} + + +static void +ngx_http_upstream_connect_handler(ngx_event_t *ev) +{ + ngx_http_request_t *r; + ngx_http_upstream_t *u; + + r = ev->data; + u = r->upstream; + ngx_http_upstream_connect(r, u); } @@ -4840,6 +4879,10 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, u->peer.connection = NULL; + if (u->event && u->event->timer_set) { + ngx_del_timer(u->event); + } + if (u->pipe) { u->pipe->upstream = NULL; } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 4560bbe9a..b6f42e79a 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -166,6 +166,7 @@ typedef struct { ngx_msec_t send_timeout; ngx_msec_t read_timeout; ngx_msec_t next_upstream_timeout; + ngx_msec_t next_upstream_delay; size_t send_lowat; size_t buffer_size; @@ -185,6 +186,7 @@ typedef struct { ngx_uint_t next_upstream; ngx_uint_t store_access; ngx_uint_t next_upstream_tries; + ngx_flag_t next_upstream_unique; ngx_flag_t buffering; ngx_flag_t request_buffering; ngx_flag_t pass_request_headers; @@ -340,6 +342,8 @@ struct ngx_http_upstream_s { ngx_peer_connection_t peer; + ngx_event_t *event; + ngx_event_pipe_t *pipe; ngx_chain_t *request_bufs; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 7b8c07414..0950e8f44 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -713,7 +713,7 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) ngx_http_upstream_rr_peers_wlock(peers); #if (NGX_HTTP_UPSTREAM_ZONE) - if (peers->config && rrp->config != *peers->config) { + if (pc->unique && peers->config && rrp->config != *peers->config) { goto busy; } #endif @@ -919,7 +919,9 @@ best_chosen: n = p / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); - rrp->tried[n] |= m; + if (pc->unique) { + rrp->tried[n] |= m; + } if (now - best->checked > best->fail_timeout) { best->checked = now; @@ -1049,7 +1051,13 @@ ngx_http_upstream_free_round_robin_peer_locked(ngx_peer_connection_t *pc, ngx_http_upstream_rr_peers_unlock(rrp->peers); - pc->tries = 0; + if (pc->unique) { + pc->tries = 0; + + } else if (pc->tries) { + pc->tries--; + } + return; }