> I agree with Tom though...let exim's internal queue functions handle
> it since it's already doing whatever you'd be scripting and it works
> in parallel.
Actually, I do run a scripted queue runner replacement for performance
reasons on my outgoing machines. I wrote this once before, but anyway:
Exim does not coordinate its queue runners. If you have too few, you
waste throughput. If you have enough, they step on each others toes
by trying to deliver messages currently being delivered by another
queue runner or by trying a message just having been tried by another
queue runner, just to find out it was just tried, while letting other
messages starve.
It is way cheaper to deliver mails instantly than to queue them first, but
if you can not but have a queue in between 15 and 150 thousand messages,
a coordinated approach might solve the problem. It certainly does it
for me. Be aware that you end up with more than 300 parallel deliveries,
though, if messages have more than one recipient. That's one reason
why Exim works differently, but my machines didn't come with a tag
"do not exceed 300 parallel deliveries", so I don't care. :-)
----------------------------------------------------------------------
#!/bin/rc
CONCURRENCY=300
echo 'Exim queue runner started.'
exec >/dev/null >[2=1] </dev/null
fn sighup {}
@{
@{ while (true) { /usr/exim/bin/exim -bpra; sleep 120 } } | awk '{
id=$3
do { getline } while ($0!="")
print "exec /usr/exim/bin/exim -Mc " id
}' | parsh $CONCURRENCY
} &
----------------------------------------------------------------------
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char ln[4096],*end;
int p,res=0,status=0,usage=0;
if (argc!=2) usage=1;
else
{
p=strtol(argv[1],&end,10);
if (*end || p<1) usage=1;
}
if (usage)
{
fprintf(stderr,"Usage: parsh parallelity\n");
exit(1);
}
while (fgets(ln,sizeof(ln),stdin))
{
if (p==0) { wait(&status); ++p; }
if (res==0 && status) res=status;
switch (vfork())
{
case 0:
{
execl("/bin/sh","sh","-c",ln,(const char*)0);
fprintf(stderr,"parsh: exec failed: %s\n",strerror(errno));
exit(2);
break;
}
case -1:
{
fprintf(stderr,"parsh: vfork failed: %s\n",strerror(errno));
exit(2);
break;
}
default: --p;
}
}
while (wait(&status)!=-1) if (res==0 && status) res=status;
return res;
}
----------------------------------------------------------------------
Michael