# Proxy\_next\_upstream and POSTs

**URL:** <https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771>\
**Category:** NGINX\
**Created:** [May 9, 2011, 6:43pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771 "2011-05-09T18:43:05Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![luislavena](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/0ea827/32.png) [@luislavena](https://www.ruby-forum.com/u/luislavena)\
**Post date:** [May 9, 2011, 6:43pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/1 "2011-05-09T18:43:05Z")

</div>

Hi!  
Nginx is great and the way it handles upstream and failed server as  
well! I  
would just like to avoid retrying request when they are POSTs, as POSTs  
are  
no idempotent and my backend can’t handle duplicated POSTs right now.  
So I started to mess around with the code. What I have in mind is to  
create  
a module that will change the behavior of proxy\_next\_upstream by just  
checking that http method != POST.  
I believe it supposed to be really simple.  
So a couple of questions for those who are into nginx source code:

1. Is there any good article, blog post, etc, that explain how to create  
and  
test a module?
2. Any good advice on how I should do it? I was thinking on adding the  
validation somewhere in ngx\_http\_upstream\_test\_next  
(ngx\_http\_upstream.c),  
something like:  
if (r-\>method == NGX\_HTTP\_POST) {  
return NGX\_DECLINED;  
}

If this is OK, how could I do this from a module? So when someone  
compiles  
nginx with this module, he’ll have this behavior instead of the standard  
one?

Sorry if my questions are dumb.

Jonathan

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 10, 2011, 12:38am UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/2 "2011-05-10T00:38:25Z")

</div>

I read some modules out there and could manage to write a custom module  
that  
will do the job. I have some doubts though.  
How can I call the original upstream module from my own upstream module?  
I  
don’t want to replace it.

I think the magic might go here:  
ngx\_http\_upstream\_init\_\_peer method. Is that right? Is  
there  
any example that I can use?

Thanks!

Jonathan

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 10, 2011, 9:23am UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/3 "2011-05-10T09:23:10Z")

</div>

Hello,

You might want to have a look at Evan’s Miller section on proxying  
handlers: [Emiller’s Guide to Nginx Module Development – Evan Miller](http://www.evanmiller.org/nginx-modules-guide.html#proxying)  
This page is pretty much considered _the_ reference for module  
development.

Enjoy,

## Antoine.

Low fare on trips to nginx land: visit [http://www.nginx-discovery.com](http://www.nginx-discovery.com)

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 10, 2011, 4:32pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/4 "2011-05-10T16:32:52Z")

</div>

Hi,

> 1. Any good advice on how I should do it? I was thinking on adding the  
> validation somewhere in ngx\_http\_upstream\_test\_next (ngx\_http\_upstream.c),  
> something like:  
> if (r-\>method == NGX\_HTTP\_POST) {  
> return NGX\_DECLINED;  
> }

Keep in mind that you should decline sending request to another backend,  
only if you already sent it upstream. There is a bunch of errors (bad  
gateway, connection timeout, etc) which could lead to the code path in  
question, for which you should still send request to another backend.

Best regards,  
Piotr S. \< [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) \>

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 10, 2011, 4:09pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/5 "2011-05-10T16:09:58Z")

</div>

Thanks! That guide was really useful.  
I almost have it done. What is missing there is how to test and maybe  
something even more generic.  
Once I finish my module I will try to write an even more basic guide  
to help people 🙂

Jonathan

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 10, 2011, 9:30pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/6 "2011-05-10T21:30:51Z")

</div>

Ok. Finally I could work it out, so thanks anyway!

Here is my small contribution to nginx, it is not much, but it is  
something.

> **[GitHub - xetorthio/nginx-upstream-idempotent: Small module for nginx that...](https://github.com/xetorthio/nginx-upstream-idempotent)**
>
> Small module for nginx that will avoid retrying failed POST requests as they are not idempotent - GitHub - xetorthio/nginx-upstream-idempotent: Small module for nginx that will avoid retrying faile...

Thanks everyone for your help, and if you have time and find something  
weired in the code, let me know!

Jonathan

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 10, 2011, 4:48pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/7 "2011-05-10T16:48:56Z")

</div>

Right, that is why after digging for a while I realized I wan’t doing it  
the  
right way.  
Now I wrote a module that will hook into the upstream logic and will set  
all  
the callbacks to the round-robin callbacks. Only the the peer.free  
callback  
will call the original round-robin callback and after that will do  
something  
like:

if (r-\>method == NGX\_HTTP\_POST) {  
pc-\>retries = 0;  
}

by setting retires = 0 I think nginx won’t retry and will fail and I  
will be  
using round-robin logic for all the rest.

My only problem is that in the peer.free callback I don’t have access to  
the  
request struct, so I don’t know is the request’s method. So now I am not  
sure if the approach is the right one.

Any thoughts on this?

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 11, 2011, 10:03am UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/8 "2011-05-11T10:03:48Z")

</div>

## Glad to hear you made it. As far as testing goes, you might find interesting (or just fun) to read my own experiences with the subject:

> **[Day 29 - nginx development tool-chain, reviewed](http://www.nginx-discovery.com/2011/02/day-29-nginx-development-tool-chain.html)**
>
> Originally, today I was planning to tell you about ngx\_str\_t and char \* but life being what it is, you will have to wait. Because today, I...

- [nginx discovery journey: Day 32 - Moving to Test::Nginx](http://www.nginx-discovery.com/2011/03/day-32-moving-to-testnginx.html)
- 

## [nginx discovery journey: Day 33 - Test::Nginx, pipelined\_requests, raw\_request and other testing tricks](http://www.nginx-discovery.com/2011/03/day-33-testnginx-pipelinedrequests.html)

[http://www.nginx-discovery.com/2011/03/day-40-testnginx-new-features.html](http://www.nginx-discovery.com/2011/03/day-40-testnginx-new-features.html)

As far as documentation of Test::Nginx goes, you might find the devel  
tree ([GitHub - openresty/test-nginx at devel · GitHub](https://github.com/agentzh/test-nginx/tree/devel)) which includes  
my commits a bit more verbose than the “master” branch.

Enjoy testing.

A.

–  
Round-trip fares to nginx land as low as $0: visit  
[http://www.nginx-discovery.com](http://www.nginx-discovery.com)

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 12, 2011, 12:36pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/9 "2011-05-12T12:36:01Z")

</div>

On Wed, May 11, 2011 at 4:03 PM, Antoine B.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> As far as documentation of Test::Nginx goes, you might find the devel  
> tree ([GitHub - openresty/test-nginx at devel · GitHub](https://github.com/agentzh/test-nginx/tree/devel)) which includes  
> my commits a bit more verbose than the “master” branch.

I’ve just merged test-nginx’s devel branch back to its master after  
massive regression testing on my side. And I’ll do a new CPAN release  
of Test::Nginx tomorrow or so 🙂

Happy hacking!  
-agentzh

---

<div class="post-metadata">

**Author:** ![johanatan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/8491ac/32.png) [@johanatan](https://www.ruby-forum.com/u/johanatan)\
**Post date:** [May 12, 2011, 12:31pm UTC](https://www.ruby-forum.com/t/proxy-next-upstream-and-posts/206771/10 "2011-05-12T12:31:41Z")

</div>

On Wed, May 11, 2011 at 4:03 PM, Antoine B.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> As far as documentation of Test::Nginx goes, you might find the devel  
> tree ([GitHub - openresty/test-nginx at devel · GitHub](https://github.com/agentzh/test-nginx/tree/devel)) which includes  
> my commits a bit more verbose than the “master” branch.

I’ve just merged test-nginx’s devel branch back to its master after  
massive regression testing on my side. And I’ll do a new CPAN release  
of Test::Nginx tomorrow or so 🙂

Happy hacking!  
-agentzh
