Terje_Gravvold
Jul 03, 2009Nimbostratus
iRule - Retry HTTP post request, including payload, to a secondary pool if primary pool fails
I've scripted a short iRule to handle resending of HTTP post requests, including XML payload/post data, to a secondary pool if primary fails. The rule is based iRule examples and forum posts.
The iRule below seems to pass the first simple web-service test. It would have been very nice if someone with similar use cases could comment this post. If members of the comunity decides to test this iRule in their own environment please comment with any results.
Case is as folows:
1. Two pools (Cells) of IBM Web-sphere Process Server (WPS)
2. The two pools runs the same processess (servces) with some exceptions.
3. Service request errors agianst primary pool should result in a retry request to secondary pool.
Service request errors are here defined as HTTP 3xx, 4xx and 5xx + connection problems. Only HTTP 2xx is accepted as a "good" reply.
iRule Attached.
Best regards
Terje Gravvold
when CLIENT_ACCEPTED {
Set initial retry count to zero
set retries 0
Set debug level for iRule
set debug 6
Set HTTP status code to look for
set status_code 5
Set info about connecting client (IP:port)
set client [IP::remote_addr]:[TCP::remote_port]
Log client info about connecting client
if { $debug > 0 } { log local0.alert "From [IP::remote_addr]:[TCP::remote_port] To: [IP::local_addr]:[TCP::local_port]" }
}
when HTTP_REQUEST {
On first try, set request variables and capture request payload (XML post data)
if { $retries == 0 } {
Set request, HTTP post header.
set request [HTTP::request]
Retrive HTTP uri from HTTP request header
set uri [HTTP::uri]
Retrive HTTP method from HTTP request header
set method [HTTP::method]
Retrive host from HTTP request header
set host [HTTP::host]
Set payload content legth to capture.
if {[HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 2048}{
set content_length [HTTP::header "Content-Length"]
}
else {
set content_length 2048
}
Capture HTTP payload from request, HTTP::collect triggers event HTTP_REQUEST_DATA
if { [info exists content_length] && $content_length > 0} {
HTTP::collect $content_length
}
Set default pool to send first request to.
pool pool_tst_wps-celle-1
Log request
if { $debug > 5 } { log local0.alert "Request: $request" }
}
}
when HTTP_REQUEST_DATA {
Set payload, depends on HTTP::collect done in HTTP_REQUEST event.
set payload [HTTP::payload]
Append HTTP payload to HTTP request header to form a complete HTTP post request (request + payload)
append request [HTTP::payload [HTTP::payload length]]
Log payload
if { $debug > 5 } { log local0.alert "Payload: $payload" }
}
when LB_SELECTED {
if { $retries == 0 } {
Log LB pool/server selection
if { $debug > 0 } { log local0.alert "Server Selected $retries: [LB::server pool] [LB::server addr]:[LB::server port]" }
}
else {
Reselect LB pool if retries > 0
LB::reselect pool pool_tst_wps-celle-2
Log LB pool/server selection
if { $debug > 0 } { log local0.alert "Server Selected $retries: [LB::server pool] [LB::server addr]:[LB::server port]" }
}
if { $debug > 5 } { log local0.alert "Request: $request" }
}
when HTTP_RESPONSE {
if { [HTTP::status] starts_with 2 } {
Check for HTTP 2xx response, else retry.
if { $debug > 0 } { log local0.alert "Process found in pool [LB::server pool], request served by pool member [LB::server addr]:[LB::server port]" }
}
else {
Retry if not HTTP 2xx response and retry count equals zero.
if { $retries == 0 } {
Increment retries by 1
incr retries
Retry HTTP request/payload to another another server. This command triggers LB_SELECTED event.
HTTP::retry "$request"
if { $debug > 0 } { log local0.alert "Process NOT found in pool [LB::server pool], detaching pool member [LB::server addr]:[LB::server port]" }
if { $debug > 5 } { log local0.alert "Request retry: $request" }
}
else {
if { $debug > 0 } { log local0.alert "Process NOT found in any pool, [HTTP::status] sent to client." }
}
}
}
when LB_FAILED {
if { $retries == 0 } {
Increment retries by 1
incr retries
Retry HTTP request/payload to another another server. This command triggers LB_SELECTED event.
HTTP::retry "$request"
if { $debug > 0 } { log local0.alert "Process NOT found in pool [LB::server pool], detaching pool member [LB::server addr]:[LB::server port]" }
if { $debug > 5 } { log local0.alert "Request retry: $request" }
}
else {
if { $debug > 0 } { log local0.alert "Process NOT found in any pool, [HTTP::status] sent to client." }
}
}