您的位置:首页 > Web前端

6.9.1.1 qmgr_defer_todo:为延迟邮件清理待发送收件人列表

2016-04-07 15:32 253 查看
/qmgr/qmgr_ defer.c
106 /* qmgr_defer_todo - defer all todoqueue entries for specific site */
107
108 void   qmgr_defer_todo(QMGR_QUEUE *queue, DSN *dsn)
109 {
110    QMGR_ENTRY *entry;
111    QMGR_ENTRY *next;
112    QMGR_MESSAGE *message;
113    RECIPIENT *recipient;
114    int     nrcpt;
115    QMGR_QUEUE *retry_queue;
116
117    /*
118     * Sanity checks.
119     */
120    if (msg_verbose)
121        msg_info("defer site %s: %s %s",
122                  queue->name,dsn->status, dsn->reason);
123
124    /*
125     * See if we can redirect the deliveries to the retry(8) delivery agent,
126     * so that they can be handled asynchronously. If the retry(8) service is
127     * unavailable, use the synchronous defer(8) server. With a large todo
128     * queue, this blocks the queue manager for a significant time.
129     */
130    retry_queue = qmgr_error_queue(MAIL_SERVICE_RETRY, dsn);


130 qmgr_defer_todo优先使用retry MDA处理暂时无法发送的QMGR_ENTRY。对于retry MDA,将为每一种遇到的DSN错误建立一个QMGR_QUEUE。

qmgr_error_queue函数查找或创建retryMDA:

/*
* Find or create transport.
*/
if ((transport = qmgr_error_transport(service)) == 0)
return(0);


为每一种DSN错误类型建立一个QMGR_QUEEN:

/*
* Find or create queue.
*/
nexthop = qmgr_error_nexthop(dsn);
if ((queue = qmgr_queue_find(transport, nexthop)) == 0)
queue= qmgr_queue_create(transport, nexthop, nexthop);


QMGR_QUEUE的名字根据DSN错误信息来构造:

/* qmgr_error_nexthop - computenext-hop information from problem description */
char   *qmgr_error_nexthop(DSN *dsn)
{
char   *nexthop;

nexthop = concatenate(dsn->status, " ", dsn->reason,(char *) 0);
return (nexthop);
}


qmgr_defer_todo会在qmgr_defer_transport或qmgr_deliver_update中被调用,分别代表两种错误:

4.3.0,错误信息为"mailtransport unavailable"

4.0.0,错误信息为”unknow error”

131
132    /*
133     * Proceed carefully. Queue entries may disappear as a side effect.
134     */
135    for (entry = queue->todo.next; entry != 0; entry = next) {
136        next = entry->queue_peers.next;
137        if (retry_queue != 0) {
138             qmgr_entry_move_todo(retry_queue,entry);
139             continue;
140        }
141        message = entry->message;
142        for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
143             recipient =entry->rcpt_list.info + nrcpt;
144             qmgr_defer_recipient(message,recipient, dsn);
145        }
146        qmgr_entry_done(entry, QMGR_QUEUE_TODO);
147    }


135-147 循环该QMGR_QUEUE的todo QMGR_ENTRY_LIST,延迟发信。

这里对延迟分两种情况处理:存在retry MDA或不存在retry MDA的情况。这样的区分支持异步方式处理。

如果存在error模块,则使用qmgr_entry_move_todo函数将原QMGR_QUEUE的todo QMGR_ENTRY_LIST移动到retry MDA的以DSN错误代码为名称的QMGR_QUEUE的todo QMGR_ENTRY_LIST:

/*
* Create new entry, swap the recipients between the two entries,
* adjusting the job counters accordingly, then dispose of the old entry.
*
* Note that qmgr_entry_done() will also take care of adjusting the
* recipient limits of all the message jobs, so we do not have to do that
* explicitly for the new job here.
*
* XXX This does not enforce the per-entry recipient limit, but that isnot
* a problem as long as qmgr_entry_move_todo() is called only to bounce
* or defer mail.
*/
dst_job = qmgr_job_obtain(message, dst_transport);
dst_peer = qmgr_peer_obtain(dst_job, dst_queue);
new_entry = qmgr_entry_create(dst_peer, message);
recipient_list_swap(&entry->rcpt_list,&new_entry->rcpt_list);


如果无法找到或建立retryQMGR_QUEUE,则调用qmgr_defer_recipient。qmgr_defer_recipient-> defer_append->defer_append_intern将直接联系bounce模块完成延迟处理工作。

148 }
149
150 /* qmgr_defer_recipient - deferdelivery of specific recipient */
151
152 void   qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
153                                      DSN *dsn)
154 {
155    MSG_STATS stats;
156
157    /*
158     * Update the message structure and log the message disposition.
159     */
160    message->flags |= defer_append(message->tflags,message->queue_id,
161                                  QMGR_MSG_STATS(&stats, message),recipient,
162                                   "none", dsn);
163 }


无论是否存在retry MDA,最终都会调用qmgr_entry_done函数,该函数最终销毁无法使用的QMGR_ENTRY结构体。如果存在retry MDA,虽然continue语句会跳出本次循环,但qmgr_entry_move_todo函数中会调用qmgr_entry_done函数。如果不存在retry MDA,则会执行qmgr_entry_done函数,该函数的第二个参数接收

#define QMGR_QUEUE_TODO 1 /* waiting for service */
#define QMGR_QUEUE_BUSY 2 /*recipients on the wire */

这两个选项,对于延迟发信,均使用选项QMGR_QUEUE_TODO。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: