Forum Discussion
catch in irule
Hi Amit,
The [catch] command allows you to execute unstable TCL syntax, that MAY run into a TCL run time error. If a error has happend you will be able to handle this, instead of crashing the TCL runtime (aka. reset the individual network connection).
The command is often used by lazy developers to make unstable code stable (aka. make the code just work stable without those errors), but it is also used by high experienced developers to write highly performance optimized code (aka. skip complex verification, see if works out and perform verification just in the case it would fail in the first try).
The [catch] command can be implemented in different ways.
Suppress errors only
catch {
log local0.debug "This will fail: $variable_does_not_exist"
... subsequent code will not become executed if the previous command fails ....
}
Note: This syntax should be only used when the action is not that important, or the functionality does not depend on the sucessful execution of the catch { command }.
Suppress errors with simple error information save into a variable
catch {
log local0.debug "This will fail: $variable_does_not_exist"
... subsequent code will not become executed if the previous command fails ....
} simple_error
if { $simple_error ne "" } then {
This code will be triggered if catch has caugth an error
log local0.debug "The catch command has catched the error: Simple Error: $simple_error"
}
Note: The simple_error variable should never be used! Since it would degrade your performance in the case the catch { command } executes successfully. Accessing the global and extended [subst \$::errorInfo] variable right after the error happend is much more CPU friendly.
Suppress errors with return code values
if { [catch {
log local0.debug "This will fail: $variable_does_not_exist"
... subsequent code will not become executed if the previous command fails ....
}] } then {
This code will be triggered if catch has caugth an error
log local0.debug "The catch command has catched the error: Extended errorInfo: [subst \$::errorInfo]"
}
Note: This syntax should be used prefered, when the functionality does depend on the sucessful execution of the catch { command }. It causes very little overhead if the catch { command } runs successfully and allows you to trigger your error handle via an if ... then ... syntax.
Your iRule (commented)
Now that you have a brief understanding of the [catch] command, lets see what the individual lines of your existing iRule are doing...
"[0-9]*" {
if { [catch {
The [member -list] command will fetch the member list of the currently selected pool > [members -list [LB::server pool]]
The fetched member list will be sorted > [lsort [members -list [LB::server pool]]
The variable $member_num will be used in a math operation > [expr { $member_num - 1}]. This could be interesting for $member_num=0 ;-)
The result of the math operation will be used to pick an entry of the member list (list positions are starting with 0) > [lindex [lsort [members -list [LB::server pool]]] [expr { $member_num - 1}]]
The picked entry of the member list will be parsed to extract the IP and Port Information > scan [lindex [lsort [members -list [LB::server pool]]] [expr { $member_num - 1}]] {%[^ ] %d} ip port
scan [lindex [lsort [members -list [LB::server pool]]] [expr { $member_num - 1}]] {%[^ ] %d} ip port
The catch command will now write the $result variable. It will hold the last "return" information. In your case the "return" information of the [scan] command (e.g. the number of extracted elements).
} result] } then {
If [catch] has for what ever reason caugth an error nothing will happen. So catch will silently supress the error and the remaining iRule will become executed...
} elseif { $result == 2} {
If [catch] didn't caugth an error and the $result of the [scan] command is 2 (aka. a IP and Port could be extracted) the pool member would be selected.
if {not [catch {pool [LB::server pool] member $ip $port}]}{
This catch part is slightly paranoid. Since the extracted member list information (e.g. IP / Port) should not throw an error at all.
Selecting pool member succeeded so exit this event of this iRule
return
}
}
}
Clean Version of your iRule
Below you will find a cleaner version of your iRule. It does the same, but slightly faster and much better to understand... 😉
"[0-9]*" {
if { [catch {
Lets try this slightly unstable but very performance optimized code without any further verification...
scan [lindex [lsort [members -list [LB::server pool]]] [expr { $member_num - 1}]] {%[^ ] %d} ip port
pool [LB::server pool] member $ip $port
}] } then {
Something went wrong with the code. Lets use the default pool then...
} else {
Everything went well. Forward traffic to the selected pool member...
return
}
}
Cheers, Kai
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com