You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@spamassassin.apache.org by "Gary W. Smith" <ga...@primeexalia.com> on 2007/02/11 20:11:50 UTC

Mail::SpamAssassin::Client oddities

Hello, 

I've been playing around with Mail::SpamAssassin::Client and overall it
seems to work pretty well with one exception.  Occasionally, on the ping
test, it fails for live servers immediately.  I have an array of 6
servers, 4 local and 2 remote (over a 1mb VPN.  I can understand the
failure possibilities for the remote SA servers, but it also happens to
the local ones as well.

Since the class is minimal, I don't see any way that I can be really
message up on the call or anything.  Is there a way to set the default
timeout for the connection on this?  It seems that if the SA servers
don't answer immediately then the ping will fail.  Each of the SA
instances are running 10 spamd threads with no more than 5 in use on
average (except for 1 server which has a no active connections, which
also see's the same timeout). 

<CODESNIPLET>
$engine = $config->{'config'}{'ENGINES'}{'SA1'}[rand
@{$config->{'config'}{'ENGINES'}{'SA1'}}];
print
$engine->{'PORT'}."\n".$engine->{'HOST'}."\n".$engine->{'USERNAME'}."\n"
;

$saclient = new SAClient({port => $engine->{'PORT'},
	host => $engine->{'HOST'},
	user => $engine->{'USERNAME'}});

if (!$saclient->ping()) {
	EALogger::eaLog($config,'err', 'Spamcheck error, ping to
['.$engine->{'HOST'}.":".$engine->{'PORT'}.":".$engine->{'USERNAME'}.']'
);
	return %retval;
}
$result = $saclient->process($msg->string());
if ($result->{"isspam"} eq 'True') {
	$spammsg{"isspam"} = 1;
	$spammsg{"score"} = $result->{"score"};
	$spammsg{"threshold"} = $result->{"threshold"};
}
else {
	$spammsg{"isspam"} = 0;
	$spammsg{"score"} = 0;
	$spammsg{"threshold"} = 0;
}
</CODESNIPLET>

I did edit the Mail::SpamAssassin::Client .pm file and tried to add an
increased timeout but that also didn't seem to help.  Is there any way I
can tweak the Client.pm to allow for a more graceful timeout?  I suspect
that in the ping area itself it's not the ideal place (probably
_create_connection would be better) but I was just testing with that.

<CODESNIPLET>
sub ping {
  my ($self) = @_;

  my $remote = $self->_create_connection();

  return 0 unless ($remote);
  # GWS Added timeout to fix broken connect
  # Failed randomly on remote SA Servers
  $remote->timeout(20);
  #print "Timeout: ".$remote->timeout()."\n";
  print $remote "PING $PROTOVERSION$EOL";
  print $remote "$EOL";

  my $line = <$remote>;
  close $remote;
  return undef unless (defined $line);

  my ($version, $resp_code, $resp_msg) =
$self->_parse_response_line($line);

  return 0 unless ($resp_msg =~ /^PONG/);

  return 1;
}
</CODESNIPLET>


Any help would be greatly appreciated.

Gary

RE: Mail::SpamAssassin::Client oddities

Posted by "Gary W. Smith" <ga...@primeexalia.com>.
> Don't bother with the ping... just try to process the message.  It'll
> fail just as fast as a ping if the spamd service isn't working.

I agree that this should be the case.  I have tested it with pointing to
a dead server in the mix and it still hangs sometimes reports that the
service is offline. (though I'm watching it on both ends and seeing that
there is no load on the SA box.

I failed to mention that my dev environment is a Xen instance on a box
with a few other instances.  I suspect, but can't confirm, that I might
be seeing an issue with setting up of TCP connections.  I'm going to
play around with that for a while to verify.

> What sort of failure are you seeing?  Are you seeing "Failed to create
> connection to spamd daemon: $!" being output on STDOUT, indicating a
> failure to setup the socket, or something else?  If something else,
you
> may want to try logging the response $line in the ping method to see
> what the response is, if any.  The spamd logs may also provide some
> clues.

When the ping fails to access one of the remote active SA instances, no
logs are recorded.  It's like the call was never answered.  
> 
> fwiw, I haven't seen this happen with my check_spamd Nagios plugin,
> which also works as a command line util, (availble from SA's svn in
> contrib/).  Nagios consistently reports "OK durations" equal to that
of
> other services on the systems that have a spamd service being checked.
> 
> I haven't noticed it happen with my milter either, which uses
> M::SA::Client, but it automatically tries other spamd services until
it
> either gets a successful scan or times out.  I haven't noticed too
many
> messages that aren't scanned by the primary spamd service for the
> particular MX (and none that aren't scanned by at most the second
spamd
> service for that MX).  So if it is failing when it shouldn't it's
rare.

I have an array of instances from a config file that I will be using.
What I will do is random load balancing and if that fails I might just
walk the array in order (or come up with some other weighed method of
doing it).

BTW, thanks for the info.

Gary 

Re: Mail::SpamAssassin::Client oddities

Posted by "Daryl C. W. O'Shea" <sp...@dostech.ca>.
Gary W. Smith wrote:
> Hello, 
> 
> I've been playing around with Mail::SpamAssassin::Client and overall it
> seems to work pretty well with one exception.  Occasionally, on the ping
> test, it fails for live servers immediately.  I have an array of 6
> servers, 4 local and 2 remote (over a 1mb VPN.  I can understand the
> failure possibilities for the remote SA servers, but it also happens to
> the local ones as well.
> 
> Since the class is minimal, I don't see any way that I can be really
> message up on the call or anything.  Is there a way to set the default
> timeout for the connection on this?  It seems that if the SA servers
> don't answer immediately then the ping will fail.  Each of the SA
> instances are running 10 spamd threads with no more than 5 in use on
> average (except for 1 server which has a no active connections, which
> also see's the same timeout). 

There is no timeout (at least AFAIK IO::Socket has no default timeout). 
   It might be a good idea to allow for a timeout to be set on the 
socket, though, so that IO::Socket can cleanup nicely.

As it is now, either the spamd service responds with the correct result 
("PONG"), it responds with something else, or it doesn't respond at all. 
  It's up to you to wrap the $client->ping call in a timeout.  Again it 
might be better if the timeout was handled internally, but it's not.


> <CODESNIPLET>
> $engine = $config->{'config'}{'ENGINES'}{'SA1'}[rand
> @{$config->{'config'}{'ENGINES'}{'SA1'}}];
> print
> $engine->{'PORT'}."\n".$engine->{'HOST'}."\n".$engine->{'USERNAME'}."\n"
> ;
> 
> $saclient = new SAClient({port => $engine->{'PORT'},
> 	host => $engine->{'HOST'},
> 	user => $engine->{'USERNAME'}});
> 
> if (!$saclient->ping()) {
> 	EALogger::eaLog($config,'err', 'Spamcheck error, ping to
> ['.$engine->{'HOST'}.":".$engine->{'PORT'}.":".$engine->{'USERNAME'}.']'
> );
> 	return %retval;
> }

Don't bother with the ping... just try to process the message.  It'll 
fail just as fast as a ping if the spamd service isn't working.


> $result = $saclient->process($msg->string());
> if ($result->{"isspam"} eq 'True') {
> 	$spammsg{"isspam"} = 1;
> 	$spammsg{"score"} = $result->{"score"};
> 	$spammsg{"threshold"} = $result->{"threshold"};
> }
> else {
> 	$spammsg{"isspam"} = 0;
> 	$spammsg{"score"} = 0;
> 	$spammsg{"threshold"} = 0;
> }
> </CODESNIPLET>
> 
> I did edit the Mail::SpamAssassin::Client .pm file and tried to add an
> increased timeout but that also didn't seem to help.  Is there any way I
> can tweak the Client.pm to allow for a more graceful timeout?  I suspect
> that in the ping area itself it's not the ideal place (probably
> _create_connection would be better) but I was just testing with that.
> 
> <CODESNIPLET>
> sub ping {
>   my ($self) = @_;
> 
>   my $remote = $self->_create_connection();
> 
>   return 0 unless ($remote);
>   # GWS Added timeout to fix broken connect
>   # Failed randomly on remote SA Servers
>   $remote->timeout(20);
>   #print "Timeout: ".$remote->timeout()."\n";
>   print $remote "PING $PROTOVERSION$EOL";
>   print $remote "$EOL";
> 
>   my $line = <$remote>;
>   close $remote;
>   return undef unless (defined $line);
> 
>   my ($version, $resp_code, $resp_msg) =
> $self->_parse_response_line($line);
> 
>   return 0 unless ($resp_msg =~ /^PONG/);
> 
>   return 1;
> }
> </CODESNIPLET>
> 
> 
> Any help would be greatly appreciated.

What sort of failure are you seeing?  Are you seeing "Failed to create 
connection to spamd daemon: $!" being output on STDOUT, indicating a 
failure to setup the socket, or something else?  If something else, you 
may want to try logging the response $line in the ping method to see 
what the response is, if any.  The spamd logs may also provide some clues.

fwiw, I haven't seen this happen with my check_spamd Nagios plugin, 
which also works as a command line util, (availble from SA's svn in 
contrib/).  Nagios consistently reports "OK durations" equal to that of 
other services on the systems that have a spamd service being checked.

I haven't noticed it happen with my milter either, which uses 
M::SA::Client, but it automatically tries other spamd services until it 
either gets a successful scan or times out.  I haven't noticed too many 
messages that aren't scanned by the primary spamd service for the 
particular MX (and none that aren't scanned by at most the second spamd 
service for that MX).  So if it is failing when it shouldn't it's rare.


Daryl