[RADIATOR] add Attributes when retrying to a new Host in AuthROUNDROBIN (radiator Digest, Vol 63, Issue 14)

David Zych dmrz at illinois.edu
Thu Oct 2 10:48:33 CDT 2014


On 08/25/2014 02:51 PM, Heikki Vatiainen wrote:
> There is now ReplyTimeoutHook in Radiator 4.13 patches. The arguments it
> is passed are the same as the arguments of NoReplyHook except that there
> are only two arguments. If you need to access the reply, 3rd argument
> with NoReplyHook, it's available via $p->{rp} as usually.
> 
> This hook is called when there is no reply from the current Host. It is
> not called for every retransmission, only when the current Host is
> deemed to have failed for the request. After the hook is called, the
> next Host is tried, if there is one.
> 
> Please let me know how it works.
> 
> Thanks,
> Heikki
> 

Hi Heikki,

It's taken me longer than I had hoped to circle back around to this, but
I wanted to say thanks very much for the new patches! I am using them
now to cope much more gracefully if one of my back-end "worker"
processes gets stalled by an external dependency (i.e. ntlm_auth).

Here are the key pieces, for the benefit of anyone else trying to
accomplish something similar.

Thanks,
David


In main instance...

# Helper AuthBy to proxy stateless inner authentication requests to
# worker instances using simple round robin.
<AuthBy ROUNDROBIN>
  Identifier workerproxy
  include %D/private/localhost.secret
  # give up if worker doesn't respond within this time
  RetryTimeout 3
  # do not retry against the same worker
  Retries 0
  # transparently work around problems affecting only a single worker,
  # but limit our attempts per request (by default, ROUNDROBIN tries
  # every Host once unless already marked down by FailureBackoffTime)
  # for two reasons: 1) eventually it will be too late for a reply to
  # be useful to the client, and 2) there might be something special
  # about this particular request that's triggering the problem.
  MaxTargetHosts 2
  FailureBackoffTime 1
  # enable workers to identify and proactively IGNORE any proxied
  # request old enough that this main instance has already given up on
  # it (note: same system, so no worries about clock skew).  This
  # ensures that we won't exacerbate an external bottleneck scenario
  # by wasting our limited resources processing stale requests.
  StripFromRequest X-Proxy-Timestamp,X-Proxy-Timeout
  AddToRequest X-Proxy-Timestamp=%t,X-Proxy-Timeout=3
  ReplyTimeoutHook sub { CITES::proxy_updateTimestamp(@_) }

  <Host 127.0.0.1>
    AuthPort %{GlobalVar:radius.authworker1.port}
  </Host>
  <Host 127.0.0.1>
    AuthPort %{GlobalVar:radius.authworker2.port}
  </Host>
  <Host 127.0.0.1>
    AuthPort %{GlobalVar:radius.authworker3.port}
  </Host>
  <Host 127.0.0.1>
    AuthPort %{GlobalVar:radius.authworker4.port}
  </Host>

  # no accounting requests should end up here
  IgnoreAccounting
</AuthBy>


# AuthRADIUS ReplyTimeoutHook: update X-Proxy-Timestamp before forwarding to
# next Host
sub proxy_updateTimestamp
{
  my $attrname = "X-Proxy-Timestamp";
  my ($p,$fp) = @_;

  $$fp->change_attr($attrname, time);
  &main::log($main::LOG_DEBUG, "Set $attrname = ".$$fp->get_attr($attrname), $$p);
}


In worker instance...

<Client 127.0.0.1>
  Identifier localhost
  include %D/private/localhost.secret
  # always handle "duplicate" requests from self
  DupInterval 0
  # identify (and log) proxied requests too old to be worth answering
  PreHandlerHook sub { CITES::ignore_expired(@_) }
</Client>

# ignore requests flagged as expired by the above hook
<Handler Client-Identifier=localhost, IGNORE_EXPIRED=1>
  Identifier localhost-ignoreExpired
  <AuthBy INTERNAL>
    DefaultResult IGNORE
  </AuthBy>
</Handler>


# PreHandlerHook for localhost Client: if the request was proxied too long
# ago to be worth answering now, log an error and set IGNORE_EXPIRED to
# trigger the Handler.
sub ignore_expired {
  my ($tsattr, $windowattr) = qw(X-Proxy-Timestamp X-Proxy-Timeout);
  my $p = shift;

  my ($ts, $window) = map { $$p->get_attr($_) || return } ($tsattr, $windowattr);

  my $age = time - $ts;
  if ($age < 0 or $age > $window) {
    $$p->add_attr('IGNORE_EXPIRED',1);
    &main::log($main::LOG_ERR, "Ignoring expired request for ".$$p->getUserName().": $tsattr is ${age}s old", $$p);
  }
}


More information about the radiator mailing list