librelist archives

« back to archive

How to wait for result?

How to wait for result?

From:
Sumej
Date:
2015-07-14 @ 11:07
Hello, 
I'm writing a service (api) which executes some flow and return a respond 
(> 15 minutes) 
I want that when api client kills a http request it will still working. 

Regards. 

Re: [falcon] How to wait for result?

From:
Andrew Stuart
Date:
2015-07-14 @ 11:38
You’ll have to get something else to execute long running requests. Have a
look at Celery, or implement some sort of queueing (there’s lots of them 
around, such as RabbitMQ) so that the request to the API puts a message on
the queue and then some other Python process executes your long running 
task each time it gets a message from the queue.

On 14 Jul 2015, at 9:07 pm, Sumej <valeranew@ukr.net> wrote:

Hello,

I'm writing a service (api) which executes some flow and return a respond 
(> 15 minutes)

I want that when api client kills a http request it will still working.


Regards.

Re: [falcon] How to wait for result?

From:
Michał Jaworski
Date:
2015-07-14 @ 11:39
You should use queue here. Your http service will then be only responsible
for delegating the work to queue that later will be handled by workers that
subscribe for new messages from that queue.

This way you http api will be able to still accept new requests and this
extensive tasks your trying to perform inside of service can be easily
handled  in asynchronous and distributed manner.

You definitely should not try to have such long connections. If you need
your client to access result of this mentioned "flow" then you should
consider allowing clients to ask for result later and retry until work is
done or be able to push messages (e.g. via web hooks) The choice of best
approach depends on your use case. If you want to have more help then you
should give more details on what you are building there.

If you are not experienced with queuing services I suggest you to start
reading about rabbitmq[1] that is very popular or just use project like
celery[2] that can handle multiple message brokers.

[1] https://www.rabbitmq.com
[2] http://www.celeryproject.org

2015-07-14 13:07 GMT+02:00 Sumej <valeranew@ukr.net>:

> Hello,
>
> I'm writing a service (api) which executes some flow and return a respond
> (> 15 minutes)
>
> I want that when api client kills a http request it will still working.
>
>
> Regards.
>

Re[2]: [falcon] How to wait for result?

From:
Sumej
Date:
2015-07-14 @ 12:00
ok, I want that when some client requests a 
http://localhost/api/service/get.json  execution of   some_function 
wouldn't stop:  app = falcon.API() def some_function(): 
     ..... app.add_route(' api/{service}/get.json ', some_function) 



You definitely should not try to have such long connections. If you need 
your client to access result of this mentioned "flow" then you should 
consider allowing clients to ask for result later and retry until work is 
done or be able to push messages (e.g. via web hooks) The choice of best 
approach depends on your use case. If you want to have more help then you 
should give more details on what you are building there. 

Regards. 

Re: [falcon] How to wait for result?

From:
Ben Meyer
Date:
2015-07-14 @ 13:12
So I've recently developed an API based on Falcon that behaves similarly
- it may take up to 30 minutes to get a response.
What I've noticed (Falcon 0.2 and 0.3) is that if the client connection
terminates for some reason, then the API still completes what it was doing.
We chose this method mostly because we did not want the additional
infrastructure to keep track of requests, and wanted our couple
end-points to be entirely stateless.

That said, I would highly suggest you move to a polling response API style:
1. Accept the job, and queue it, returning a 202 and a
transaction/request id
2. Have another end-point to be able to query the status (working,
completed, canceled, etc) of the transaction/request id
3. Have a third end-point to get the result

The Falcon app is running under gunicorn, proxied by nginx. All the
default timeouts for nginx had to change to very high numbers.
Additionally, any load balancer used must also be able to support the
high timeouts, as must your client.

So while it is doable, if you can at all use the polling API style.
It'll save you a lot of headaches.

$0.02

Ben

On 07/14/2015 08:00 AM, Sumej wrote:
> ok,
> I want that when some client requests a
> http://localhost/api/service/get.json execution of  /some_function
> /wouldn't stop: 
> app = falcon.API()
> /def some_function():/
> /     ...../
> /app.add_route('/api/{service}/get.json/', some_function)/
>
>
>
>     You definitely should not try to have such long connections. If
>     you need your client to access result of this mentioned "flow"
>     then you should consider allowing clients to ask for result later
>     and retry until work is done or be able to push messages (e.g. via
>     web hooks) The choice of best approach depends on your use case.
>     If you want to have more help then you should give more details on
>     what you are building there.
>
>
> Regards.
> ! 

Re: [falcon] How to wait for result?

From:
Andrew Stuart
Date:
2015-07-14 @ 13:31
>>So I've recently developed an API based on Falcon that behaves similarly
- it may take up to 30 minutes to get a response.

You might be able to make it work but it’s still not an ideal way to write
a web application. Requests tyhpically don't remain open that long and you
don’t have control over what might be in between your server and the 
client - there may be devices such as proxies or routers or something else
that has its own connection timeouts that aren’t wound out to extremely 
long durations.  If something in between breaks the connection then the 
outcomes from that point depend on your application design.  Presumably 
the long running task will be dropped and the client will need to ask for 
it to be started again, depending on the number of clients and volume of 
responses this could lead to a real meltdown. Depending on your traffic 
also you’ll need to be careful becaus each long running request will/might
tie up web server resources and possibly prevent additional client 
connections beyond some limit which may be low or high.

You could try something like websockets if you want long running 
connections but even websockets is subject to the same sorts of issues - 
i.e. the Internet infrastructure isn’t necessarily going to play nicely 
with it - have a look at the detail of something like how socket.io is 
implemented to see the lengths they have had to go to handling all sorts 
of error conditions and fallbacks.  Again, it MIGHT work fine.

Python makes it super simple to do queueing so no real reason not to.

>>What I've noticed (Falcon 0.2 and 0.3) is that if the client connection 
terminates for some reason, then the API still completes what it was 
doing.
Interesting, I wonder if this is intentional, maybe all web servers 
complete requests where the client has dropped but I didn’t imagine things
worked that way - not something I have ever thought about thought.

Re: [falcon] How to wait for result?

From:
Ben Meyer
Date:
2015-07-14 @ 13:40
On 07/14/2015 09:31 AM, Andrew Stuart wrote:
>> So I've recently developed an API based on Falcon that behaves 
similarly - it may take up to 30 minutes to get a response.
> You might be able to make it work but it’s still not an ideal way to 
write a web application. Requests tyhpically don't remain open that long 
and you don’t have control over what might be in between your server and 
the client - there may be devices such as proxies or routers or something 
else that has its own connection timeouts that aren’t wound out to 
extremely long durations.  If something in between breaks the connection 
then the outcomes from that point depend on your application design.  
Presumably the long running task will be dropped and the client will need 
to ask for it to be started again, depending on the number of clients and 
volume of responses this could lead to a real meltdown. Depending on your 
traffic also you’ll need to be careful becaus each long running request 
will/might tie up web server resources and possibly prevent additional 
client connections beyond some limit which may be low or high.
>
> You could try something like websockets if you want long running 
connections but even websockets is subject to the same sorts of issues - 
i.e. the Internet infrastructure isn’t necessarily going to play nicely 
with it - have a look at the detail of something like how socket.io is 
implemented to see the lengths they have had to go to handling all sorts 
of error conditions and fallbacks.  Again, it MIGHT work fine.
>
> Python makes it super simple to do queueing so no real reason not to.

As I said, the polling method style will save you a lot of headaches.
We're still trying to figure out some of the issues, though right now
they're not between our API and our client; they're on the other side -
between our API and another upstream service.

>>> What I've noticed (Falcon 0.2 and 0.3) is that if the client 
connection terminates for some reason, then the API still completes what 
it was doing.
> Interesting, I wonder if this is intentional, maybe all web servers 
complete requests where the client has dropped but I didn’t imagine things
worked that way - not something I have ever thought about thought.

I don't know if it was intentional or not; but the Falcon app doesn't
seem to get any kind of notice that its client went away. So it ends up
completing without any issues; of course there are issues if it tries to
write back to the client. Though it could be that the configuration of
nginx+gunicorn is saving the day in this case too; nginx records the
early termination (499) of the client; it may just let it's upstream
complete normally still though.

$0.02

Ben

Re[2]: [falcon] How to wait for result?

From:
Sumej
Date:
2015-07-15 @ 05:51
 >"Ben Meyer" < ben.meyer@rackspace.com >: 

>That said, I would highly suggest you move to a polling response API style: 
>1. Accept the job, and queue it, returning a 202 and a transaction/request id 
>2. Have another end-point to be able to query the status (working, 
completed, canceled, etc) of the transaction/request id 
>3. Have a third end-point to get the result 

So, I create: 
app = falcon.API() class some_function: def on_post(....):  id = 
push_to_queque(**kwargs) if id is not None: msg = {"id": id} resp.body = 
json.dumps(msg, sort_keys=True, indent=4) resp.status = falcon.HTTP_202 
app.add_route('api/{service}/get.json', some_function) 

Where push_to_queue() adds parameters to the queue. I don't understand how
will called code to processed queues? I understand that when I try get 
response on uri falcon will called a function, but how to call process a 
queues? 
Regards. 


The Falcon app is running under gunicorn, proxied by nginx. All the 
default timeouts for nginx had to change to very high numbers. 
Additionally, any load balancer used must also be able to support the high
timeouts, as must your client. 

So while it is doable, if you can at all use the polling API style. It'll 
save you a lot of headaches. 

$0.02 

Ben 

On 07/14/2015 08:00 AM, Sumej wrote: 
ok, I want that when some client requests a 
http://localhost/api/service/get.json   execution of   some_function 
wouldn't stop:  app = falcon.API() def some_function(): 
     ..... app.add_route(' api/{service}/get.json ', some_function) 



You definitely should not try to have such long connections. If you need 
your client to access result of this mentioned "flow" then you should 
consider allowing clients to ask for result later and retry until work is 
done or be able to push messages (e.g. via web hooks) The choice of best 
approach depends on your use case. If you want to have more help then you 
should give more details on what you are building there. 

Regards. ! 

Re: [falcon] How to wait for result?

From:
Andrew Stuart
Date:
2015-07-15 @ 06:25
You would write a separate, standalone Python script - not a web application.

The python script will periodically poll the queue to see if any messages 
are available, and when it gets a message, will process it.  Most queues 
also provide some way to immediately execute as soon as a message becomes 
available.

You run this script on the same server - I use supervisor 
http://supervisord.org/ to run my queue processing scripts.





On 15 Jul 2015, at 3:51 pm, Sumej <valeranew@ukr.net> wrote:

 >"Ben Meyer" <ben.meyer@rackspace.com>:

>That said, I would highly suggest you move to a polling response API style:
>1. Accept the job, and queue it, returning a 202 and a transaction/request id
>2. Have another end-point to be able to query the status (working, 
completed, canceled, etc) of the transaction/request id
>3. Have a third end-point to get the result

So, I create:

app = falcon.API()
class some_function:
	def on_post(....): 
		id = push_to_queque(**kwargs)
		if id is not None:
			msg = {"id": id}
			resp.body = json.dumps(msg, sort_keys=True, indent=4)
			resp.status = falcon.HTTP_202
app.add_route('api/{service}/get.json', some_function)


Where push_to_queue() adds parameters to the queue.
I don't understand how will called code to processed queues?
I understand that when I try get response on uri falcon will called a 
function, but how to call process a queues?

Regards.



The Falcon app is running under gunicorn, proxied by nginx. All the 
default timeouts for nginx had to change to very high numbers.
Additionally, any load balancer used must also be able to support the high
timeouts, as must your client.

So while it is doable, if you can at all use the polling API style. It'll 
save you a lot of headaches.

$0.02

Ben

On 07/14/2015 08:00 AM, Sumej wrote:
> ok,
> I want that when some client requests a 
http://localhost/api/service/get.json execution of  some_function wouldn't
stop: 
> app = falcon.API()
> def some_function(): 
>      .....
> app.add_route('api/{service}/get.json', some_function)
> 
> 
> 
> You definitely should not try to have such long connections. If you need
your client to access result of this mentioned "flow" then you should 
consider allowing clients to ask for result later and retry until work is 
done or be able to push messages (e.g. via web hooks) The choice of best 
approach depends on your use case. If you want to have more help then you 
should give more details on what you are building there.
> 
> Regards.
> !



Re: [falcon] How to wait for result?

From:
Ben Meyer
Date:
2015-07-15 @ 13:18
Some other choices:

celery - http://www.celeryproject.org/
taskflow - https://wiki.openstack.org/wiki/TaskFlow

Some choices - like the above - provide a producer/consumer model
built-in so you just write a widget/task to work inside their paradigm;
others you use tools like AMQP/RabbitMQ/OpenStack Zaqar to do the
queuing and then add your own software stack to do the work. Each tool
has its benefits and issues; so you have to find the one that fits what
you're doing, makes sense to you, and remains in budget/time.

There are probably some on this list that have used several tools and
could be more helpful as to your particular needs for the first part of
the question.

Ben

On 07/15/2015 02:25 AM, Andrew Stuart wrote:
> You would write a separate, standalone Python script - not a web application.
>
> The python script will periodically poll the queue to see if any 
messages are available, and when it gets a message, will process it.  Most
queues also provide some way to immediately execute as soon as a message 
becomes available.
>
> You run this script on the same server - I use supervisor 
http://supervisord.org/ to run my queue processing scripts.
>
>
>
>
>
> On 15 Jul 2015, at 3:51 pm, Sumej <valeranew@ukr.net> wrote:
>
>  >"Ben Meyer" <ben.meyer@rackspace.com>:
>
>> That said, I would highly suggest you move to a polling response API style:
>> 1. Accept the job, and queue it, returning a 202 and a transaction/request id
>> 2. Have another end-point to be able to query the status (working, 
completed, canceled, etc) of the transaction/request id
>> 3. Have a third end-point to get the result
> So, I create:
>
> app = falcon.API()
> class some_function:
> 	def on_post(....): 
> 		id = push_to_queque(**kwargs)
> 		if id is not None:
> 			msg = {"id": id}
> 			resp.body = json.dumps(msg, sort_keys=True, indent=4)
> 			resp.status = falcon.HTTP_202
> app.add_route('api/{service}/get.json', some_function)
>
>
> Where push_to_queue() adds parameters to the queue.
> I don't understand how will called code to processed queues?
> I understand that when I try get response on uri falcon will called a 
function, but how to call process a queues?
>
> Regards.
>
>
>
> The Falcon app is running under gunicorn, proxied by nginx. All the 
default timeouts for nginx had to change to very high numbers.
> Additionally, any load balancer used must also be able to support the 
high timeouts, as must your client.
>
> So while it is doable, if you can at all use the polling API style. 
It'll save you a lot of headaches.
>
> $0.02
>
> Ben
>
> On 07/14/2015 08:00 AM, Sumej wrote:
>> ok,
>> I want that when some client requests a 
http://localhost/api/service/get.json execution of  some_function wouldn't
stop: 
>> app = falcon.API()
>> def some_function(): 
>>      .....
>> app.add_route('api/{service}/get.json', some_function)
>>
>>
>>
>> You definitely should not try to have such long connections. If you 
need your client to access result of this mentioned "flow" then you should
consider allowing clients to ask for result later and retry until work is 
done or be able to push messages (e.g. via web hooks) The choice of best 
approach depends on your use case. If you want to have more help then you 
should give more details on what you are building there.
>>
>> Regards.
>> !
>
>
>
>

Re: [falcon] How to wait for result?

From:
Andrew Stuart
Date:
2015-07-14 @ 12:23
If your requirement is that execution of the request won’t stop then you 
are building it wrong.

If you can explain in more detail exactly what you are trying to do then 
we can explain why the previous two answers to your question are still 
correct.

as


On 14 Jul 2015, at 10:00 pm, Sumej <valeranew@ukr.net> wrote:

ok,
I want that when some client requests a 
http://localhost/api/service/get.json execution of  some_function wouldn't
stop: 
app = falcon.API()
def some_function(): 
     .....
app.add_route('api/{service}/get.json', some_function)



You definitely should not try to have such long connections. If you need 
your client to access result of this mentioned "flow" then you should 
consider allowing clients to ask for result later and retry until work is 
done or be able to push messages (e.g. via web hooks) The choice of best 
approach depends on your use case. If you want to have more help then you 
should give more details on what you are building there.

Regards.