int period_seconds=30;
int filepoll_seconds=5;
int max_queue_per_ipf=-1;
+int defer_all_max_per_sec=10;
+int defer_all_burst_pause=10;
int connection_setup_timeout=200;
int inndcomm_flush_timeout=100;
{0,"no-check-proportion", "PERCENT", &nocheck_thresh, op_double },
{0,"no-check-response-time","ARTICLES", &nocheck_decay, op_double },
+{0,"defer-all-max-per-sec", "ARTICLES", &defer_all_max_per_sec, op_integer },
+{0,"defer-all-burst-pause", "TIME", &defer_all_burst_pause, op_seconds },
{0,"reconnect-interval", "PERIOD", &reconnect_delay_periods, op_seconds },
{0,"flush-retry-interval", "PERIOD", &flushfail_retry_periods, op_seconds },
extern int max_connections, max_queue_per_conn, target_max_feedfile_size;
extern int period_seconds, filepoll_seconds, max_queue_per_ipf;
extern int connection_setup_timeout, inndcomm_flush_timeout;
+extern int defer_all_max_per_sec, defer_all_burst_pause;
extern double nocheck_thresh;
extern double nocheck_decay;
/*========== handling responses from peer ==========*/
+static int defer_consecutive_count;
+
const oop_rd_style peer_rd_style= {
OOP_RD_DELIM_STRIP, '\n',
OOP_RD_NUL_FORBID,
code_streaming= (streaming); \
GET_ARTICLE(musthavesent); \
article_done(art, RC_##how); \
+ defer_consecutive_count = 0; \
goto dealtwith; \
}while(0)
case 436: /* IHAVE says try later */
GET_ARTICLE(0);
article_defer(art, RC_deferred);
+
+ // Some implementations don't reject connections when they're expiring
+ // etc., but accept them and defer every article. If such a situation
+ // persists, we will run through the entire backlog each retry interval
+ // getting the same answer to each. We try to detect this. If we only
+ // seem to be getting deferrals, we pause the whole feed.
+ defer_consecutive_count += 1;
+ if (defer_consecutive_count
+ > defer_all_max_per_sec * defer_all_burst_pause) {
+ warn("%d consecutive deferrals, pausing %ds; last response: %s",
+ defer_consecutive_count, defer_all_burst_pause, data);
+ defer_consecutive_count = 0;
+ // This causes the *whole program* including the entire event loop
+ // to freeze. That is, surprisingly, what we want. When we wake up
+ // hopefully things are better. If not we will keep sleeping here,
+ // and making no progress - which is as expected.
+ sleep(defer_all_burst_pause);
+ }
break;
}