deliver(struct qitem *it)
{
int error;
- unsigned int backoff = MIN_RETRY;
+ unsigned int backoff = MIN_RETRY, slept;
struct timeval now;
struct stat st;
MAX_TIMEOUT);
goto bounce;
}
- if (sleep(backoff) == 0) {
+ for (slept = 0; slept < backoff;) {
+ slept += SLEEP_TIMEOUT - sleep(SLEEP_TIMEOUT);
+ if (flushqueue_since(slept)) {
+ backoff = MIN_RETRY;
+ goto retry;
+ }
+ }
+ if (slept >= backoff) {
/* pick the next backoff between [1.5, 2.5) times backoff */
backoff = backoff + backoff / 2 + random() % backoff;
if (backoff > MAX_RETRY)
}
if (doqueue) {
+ flushqueue_signal();
if (load_queue(&queue) < 0)
errlog(1, "can not load queue");
run_queue(&queue);
#define MIN_RETRY 300 /* 5 minutes */
#define MAX_RETRY (3*60*60) /* retry at least every 3 hours */
#define MAX_TIMEOUT (5*24*60*60) /* give up after 5 days */
+#define SLEEP_TIMEOUT 30 /* check for queue flush every 30 seconds */
#ifndef PATH_MAX
#define PATH_MAX 1024 /* Max path len */
#endif
#error Please define LIBEXEC_PATH
#endif
+#define SPOOL_FLUSHFILE "flush"
+
#define DMA_ROOT_USER "mail"
#define DMA_GROUP "mail"
void delqueue(struct qitem *);
int acquirespool(struct qitem *);
void dropspool(struct queue *, struct qitem *);
+int flushqueue_since(unsigned int);
+int flushqueue_signal(void);
/* local.c */
int deliver_local(struct qitem *);
fclose(it->mailf);
}
}
+
+int
+flushqueue_since(unsigned int period)
+{
+ struct stat st;
+ struct timeval now;
+ char *flushfn = NULL;
+
+ if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0)
+ return (0);
+ if (stat(flushfn, &st) < 0) {
+ free(flushfn);
+ return (0);
+ }
+ free(flushfn);
+ flushfn = NULL;
+ if (gettimeofday(&now, 0) != 0)
+ return (0);
+
+ /* Did the flush file get touched within the last period seconds? */
+ if (st.st_mtim.tv_sec + period >= now.tv_sec)
+ return (1);
+ else
+ return (0);
+}
+
+int
+flushqueue_signal(void)
+{
+ char *flushfn = NULL;
+ int fd;
+
+ if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0)
+ return (-1);
+ fd = open(flushfn, O_CREAT|O_RDONLY, 0440);
+ if (fd < 0) {
+ syslog(LOG_ERR, "could not open flush file: %m");
+ free(flushfn);
+ return (-1);
+ }
+ close(fd);
+ if (utimes(flushfn, NULL) < 0) {
+ syslog(LOG_ERR, "could not touch flush file: %m");
+ free(flushfn);
+ return (-1);
+ }
+ free (flushfn);
+ return (0);
+}