= The redundant-load-balance Statement

.Syntax
[source,unlang]
----
redundant-load-balance [ <key> ] {
    [ statements ]
}
----

The `redundant-load-balance` section operates as a combination of the
xref:unlang/redundant.adoc[redundant] and xref:unlang/load-balance.adoc[load-balance]
sections.

<key>:: An attribute reference or expansion which will be hashed in
order to select the statement to execute.
+
The hash will be used to pick a particular statement within the
`load-balance` section.  This "keyed" load-balance can be used to
deterministically shard requests across multiple modules.
+
When the `<key>` field is omitted, the module is chosen randomly, in a
"load balanced" manner.

[ statements ]:: One or more `unlang` commands.
+
If the selected statement succeeds, then the server stops processing
the `redundant-load-balance` section. If, however, that statement fails,
then the next statement in the list is chosen (wrapping around to the
top).  This process continues until either one statement succeeds or all
of the statements have failed.
+
All of the statements in the list should be modules, and of the same
type (e.g., `ldap` or `sql`). All of the statements in the list should
behave identically, otherwise different requests will be processed
through different modules and will give different results.

.Example
[source,unlang]
----
redundant-load-balance &User-Name {
    sql1
    sql2
    sql3
}
----

== Redundant-load-balance Sections as Modules

It can be useful to use the same `redundant-load-balance` section in multiple
places.  Instead of copying the same text multiple times, a
`redundant-load-balance` section can be defined as a module in the `mods-enabled/`
directory.

For example, the following text can be placed into the file
`mods-enabled/sql_all`.  Once it is there, it can be used as a module
named `sql_all`, and used anywhere a module is allowed to use.

.Example of Redundant-Load-Balance SQL module
[source,unlang]
----
redundant-load-balance sql_all {
    sql1
    sql2
    sql3
}
----

In previous versions of the server, this definition would be placed
into the `instantiate` section of `radiusd.conf.  This configuration
is no longer used, and the `sql_all` definition can just be placed as
a module definition into the `mods-enabled/` directory.

== Redundant-Load-Balance Expansions

When the `sql_all` module is defined as above, it can also be used as
in a xref:xlat/index.adoc[dynamic expansion]:

.Example of Redundant-Load-Balance SQL module
[source,unlang]
----
&Reply-Message := %sql_all("SELECT message FROM table WHERE name='%{User-Name}'")
}
----

The expansion works exactly like a `redundant-load-balance` block.
One of the underlying modules is chosen.  If it fails, the next one is
chosen, etc.

The one caveat here is that the arguments passed to the underlying
modules are expanded again _for each call_.  If the expansion
arguments have side effects, then those side effects can be applied
multiple times, once for each `redundant-load-balance` attempt.

// Copyright (C) 2021 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
// This documentation was developed by Network RADIUS SAS.
