<!-- -*- mode:text coding:euc-jp -*-
    $FML: queue.sgml,v 1.9 2008/08/18 13:21:42 fukachan Exp $
-->


<sect1 id="message.queue.incoming">
	<TITLE>
	&fml8; がメールを読みこむ際のキューイング
	</TITLE>

<para>
&fml8; (以下 fml)の各プロセスは MTA から起動され、
STDIN(標準入力)からメールを読みこみます。
</para>

<para>
fml は、いったんメールを読みこみ、
まずはディスクに書き込みます(incoming queue へ書き込む)。
書き込みに成功した場合、
その書き込んだファイルに対してメッセージの解析をスタートします。
これにより、少なくとも読みこんだオリジナルのメールの記録は残せます。
</para>

<para>
もし、失敗した場合、exit(EX_TEMPFAIL)します。
たいていの OS では exit(75) です。
このエラーコードをうけとると、
MTA は一時的なエラーがおこったとみなすため、
このメッセージの再送処理を試みてくれます
(つまり、何分か後に、もう一度、最初から処理が試みられます)。
</para>

<para>
失敗が一時的なディスク溢れ(file system full)なら、
MTA の再送処理でリトライが行なわれ、ＭＬの処理が行なわれます。
ただ、ＭＬのスプールに用意したファイルシステムでのディスク溢れ
(filesystem full)が一時的とは考えにくいので、
システム管理者が気づかないと、
ずっとエラーになり続ける可能性が高いと思います。
</para>

<para>
incoming queue の処理は Mail::Delivery::Queue を使い、
ＭＬ固有の queue で管理されます。
一連の処理が終ると、たいてい、そのプロセスの最後に、このキューは消されます。
</para>

</sect1>


<sect1 id="message.queue.outgoing">
	<TITLE>
	&fml8; からメールで返事を送り返す
	</TITLE>

<para>
送り返すべきメールは
Mail::Delivery::Queue
クラスを用いて、ＭＬ固有のキューに入ります。
キューに入ったメールは、のちに
FML::Process::QueueManager
クラス経由で(配送)処理が行なわれます。
</para>

<para>
微妙に処理が異なりますが、記事の配送もコマンドメールも同様に
Mail::Delivery::Queue ベースのキューイング処理をしています。
そのため、
配送処理の途中でエラーが起きた場合、
別の &fml8; プロセスにより再送処理が行なわれます。
</para>

<sect2>
	<title>
	&fml8; の中では送信処理をどのように書くのか？
	</title>

<para>
あるメッセージ(テキストメッセージ)を送り返したい場合、次のように書きます。
<screen>
$curproc->reply_message( "you are not a ML member." );
</screen>
この場合の受信者は、投稿を拒否された人やコマンドの結果などを受けとる人、
つまり &fml8; に何かの処理を要求した人です。
</para>


<para>
ファイルを送りたい場合や画像ファイルを送りたい場合は次のようにします。
<screen>
$curproc->reply_message( {
        type        => "text/plain; charset=iso-2022-jp",
        path        => "/usr/local/etc/fml/main.cf",
        filename    => "main.cf",
        disposition => "main.cf example",
    });

$curproc->reply_message( {
        type        => "image/gif",
        path        => "/some/where/logo001.gif",
        filename    => "logo.gif",
        disposition => "attachment",
    });
</screen>
</para>

</sect2>

</sect1>


<sect1 id="message.queue">
	<TITLE>
	&fml8; におけるメールキューと配送の仕組み
	</TITLE>

<para>
FML::Process::QueueManager により
(1) 特定のキューファイルがメールキューディレクトリから pickup され、
(2) Mail::Message で parse され、
(3) FML::Mailer 経由で Mail::Delivery が実際のメール配送処理を行ないます。
<screen>
Mail::Delivery::Queue
   ↓
   ↓→→→ キューディレクトリ
   ↓
FML::Process::QueueManager
   ↓
   ↓←←← キューディレクトリ
   ↓
FML::Mailer
   ↓
Mail::Delivery
</screen>
</para>

<para>
キューを操作する際には、対象のキューを flock(2) します。
ロックを他の ATOMIC 操作を使って実装してもよいのですが、
操作途中に OS が逝ってしまうケースを想定すると、
やはり flock(2) を使うべきでしょう。
</para>

</sect1>


<sect1 id="message.queue.directory">
	<TITLE>
	メールキューディレクトリ
	</TITLE>

<para>
キューディレクトリは次のように複数のディレクトリからなります。
<screen>
new/
active/
incoming/
deferred/
info/sender/
info/recipients/
info/transport/
isolated/
</screen>
info/ には envelope 情報が格納されます。
isolated/ は隔離された不正なメール（ほぼ 100 % SPAM)置場です。
また incoming/ は incoming queue ですが、
それ以外のディレクトリは outgoing 用です。
</para>

<para>
outgoing の キューファイルを作る時は、一旦 new/ に作成します。
キューファイルを作る作業が終了し、
配送準備 OK となったら
new/ から active/ に移動されます。
つまり active/ にあるファイルは配送準備ができているものです。
</para>

<para>
処理の途中でエラーが起こったら、new/ に残骸が残ります。
定期的にゴミは消すようにしていますが、しばらくは残るわけです。
そのあいだは救出するチャンスともいえますね。
</para>

<sect2>
	<title>
	queue ディレクトリをロックする
	</title>

<para>
特定の $queue_id object ごとに lock() と unlock() メソッドを使い、
ロックをかけます。
ロックは active/$queue_id ファイルに対しての flock(2) システムコールです。
</para>
</sect2>

</sect1>
