Forum Discussion
Terje_Gravvold
Nimbostratus
Jul 03, 2009iRule - 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." }
}
}
7 Replies
- hoolio
Cirrostratus
That looks very good. You could add this to the Codeshare (Click here).
You might consider only retrying if the response code is a 50x. An app will respond with a 30x redirect in many scenarios. Likewise, clients (particularly search engine spiders) will often make requests to non-existent objects which generate a 40x response. It would add unnecessary latency and load to retry these requests.
Aaron - David_Carlin_20
Nimbostratus
Thanks for this code. We just implemented it and I wanted to share some changes we made to make it a little more robust.
Firstly, you set a lot of variables that you don't use: client, uri, method and host
Limiting content-length to 2048 doesn't allow large form submissions. Looking through the forum we realized we can increase this to 4000000 without running into the 4Mb limitation.
In rare occasions it wasn't resetting retries to 0, which was causing it to go to the second pool when it shouldn't. So in the else of LB_SELECTED we set retries to 0 again to get around this.
Hope this helps someone :)
Dave - hoolio
Cirrostratus
Hi David,
Do you want to post your cleaned up version? You or we could post it to the iRule Codeshare:
http://devcentral.f5.com/wiki/default.aspx/iRules/codeshare
Thanks, Aaron - David_Carlin_20
Nimbostratus
Done - hoolio
Cirrostratus
Thanks a lot for the fixes and posting it in the Codeshare :)
Aaron - David_Carlin_20
Nimbostratus
I'm having some trouble doing file uploads (jpg images) with this rule. Any ideas?
Does the HTTP::collect or HTTP::payload not work with binary data?
Is there another function I should be using?
Dave - Jaz_170005
Nimbostratus
thank you for sharing! helped me in a use case I am working on it.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* 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
Discover DevCentral Connects