]> source.dussan.org Git - rspamd.git/commitdiff
[Rework] Try to resolve failed upstreams more agressively
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 25 Mar 2021 20:24:31 +0000 (20:24 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 25 Mar 2021 20:24:54 +0000 (20:24 +0000)
src/libutil/upstream.c

index 6123540434fc3b626a62e4763b61fbba8dbc3be3..889b524acf7c3348a272692dbba43cfab60cd8c6 100644 (file)
@@ -59,6 +59,7 @@ struct upstream {
        gchar *name;
        ev_timer ev;
        gdouble last_fail;
+       gdouble last_resolve;
        gpointer ud;
        enum rspamd_upstream_flag flags;
        struct upstream_list *ls;
@@ -127,6 +128,10 @@ struct upstream_ctx {
         rspamd_upstream_log_id, "upstream", upstream->uid, \
         G_STRFUNC, \
         __VA_ARGS__)
+#define msg_info_upstream(...)   rspamd_default_log_function (G_LOG_LEVEL_INFO, \
+        "upstream", upstream->uid, \
+        G_STRFUNC, \
+        __VA_ARGS__)
 
 INIT_LOG_MODULE(upstream)
 
@@ -623,42 +628,64 @@ rspamd_upstream_revive_cb (struct ev_loop *loop, ev_timer *w, int revents)
 
 static void
 rspamd_upstream_resolve_addrs (const struct upstream_list *ls,
-               struct upstream *up)
+               struct upstream *upstream)
 {
-       if (up->ctx->res != NULL &&
-                       up->ctx->configured &&
-                       up->dns_requests == 0 &&
-                       !(up->flags & RSPAMD_UPSTREAM_FLAG_NORESOLVE)) {
+       /* XXX: maybe make it configurable */
+       static const gdouble min_resolve_interval = 60.0;
+
+       if (upstream->ctx->res != NULL &&
+               upstream->ctx->configured &&
+               upstream->dns_requests == 0 &&
+               !(upstream->flags & RSPAMD_UPSTREAM_FLAG_NORESOLVE)) {
+
+               gdouble now = ev_now (upstream->ctx->event_loop);
+
+               if (now - upstream->last_resolve < min_resolve_interval) {
+                       msg_info_upstream ("do not resolve upstream %s as it was checked %.0f "
+                                         "seconds ago (%.0f is minimum)",
+                                       upstream->name, now - upstream->last_resolve,
+                                       min_resolve_interval);
+
+                       return;
+               }
+
                /* Resolve name of the upstream one more time */
-               if (up->name[0] != '/') {
-                       if (up->flags & RSPAMD_UPSTREAM_FLAG_SRV_RESOLVE) {
-                               if (rdns_make_request_full (up->ctx->res,
-                                               rspamd_upstream_dns_srv_cb, up,
+               if (upstream->name[0] != '/') {
+                       upstream->last_resolve = now;
+
+                       if (upstream->flags & RSPAMD_UPSTREAM_FLAG_SRV_RESOLVE) {
+                               if (rdns_make_request_full (upstream->ctx->res,
+                                               rspamd_upstream_dns_srv_cb, upstream,
                                                ls->limits->dns_timeout, ls->limits->dns_retransmits,
-                                               1, up->name, RDNS_REQUEST_SRV) != NULL) {
-                                       up->dns_requests++;
-                                       REF_RETAIN (up);
+                                               1, upstream->name, RDNS_REQUEST_SRV) != NULL) {
+                                       upstream->dns_requests++;
+                                       REF_RETAIN (upstream);
                                }
                        }
                        else {
-                               if (rdns_make_request_full (up->ctx->res,
-                                               rspamd_upstream_dns_cb, up,
+                               if (rdns_make_request_full (upstream->ctx->res,
+                                               rspamd_upstream_dns_cb, upstream,
                                                ls->limits->dns_timeout, ls->limits->dns_retransmits,
-                                               1, up->name, RDNS_REQUEST_A) != NULL) {
-                                       up->dns_requests++;
-                                       REF_RETAIN (up);
+                                               1, upstream->name, RDNS_REQUEST_A) != NULL) {
+                                       upstream->dns_requests++;
+                                       REF_RETAIN (upstream);
                                }
 
-                               if (rdns_make_request_full (up->ctx->res,
-                                               rspamd_upstream_dns_cb, up,
+                               if (rdns_make_request_full (upstream->ctx->res,
+                                               rspamd_upstream_dns_cb, upstream,
                                                ls->limits->dns_timeout, ls->limits->dns_retransmits,
-                                               1, up->name, RDNS_REQUEST_AAAA) != NULL) {
-                                       up->dns_requests++;
-                                       REF_RETAIN (up);
+                                               1, upstream->name, RDNS_REQUEST_AAAA) != NULL) {
+                                       upstream->dns_requests++;
+                                       REF_RETAIN (upstream);
                                }
                        }
                }
        }
+       else if (upstream->dns_requests != 0) {
+               msg_info_upstream ("do not resolve upstream %s as another request for "
+                                        "resolving has been already issued",
+                                        upstream->name);
+       }
 }
 
 static void
@@ -757,6 +784,11 @@ rspamd_upstream_fail (struct upstream *upstream,
                        upstream->last_fail = sec_cur;
                        upstream->errors = 1;
 
+                       if (upstream->ls && upstream->dns_requests == 0) {
+                               /* Try to re-resolve address immediately */
+                               rspamd_upstream_resolve_addrs (upstream->ls, upstream);
+                       }
+
                        DL_FOREACH (upstream->ls->watchers, w) {
                                if (w->events_mask & RSPAMD_UPSTREAM_WATCH_FAILURE) {
                                        w->func (upstream, RSPAMD_UPSTREAM_WATCH_FAILURE, 1, w->ud);