# Thread-less long-polling

**URL:** <https://discuss.tryton.org/t/thread-less-long-polling/960>\
**Category:** Feature\
**Created:** [December 14, 2018, 2:25pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960 "2018-12-14T14:25:10Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)\
**Post date:** [December 14, 2018, 2:25pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/1 "2018-12-14T14:25:10Z")

</div>

## Rational

The current implementation of [long-polling](https://bugs.tryton.org/issue7537) creates a thread or a process per connection. This comes from the design of WSGI server (used: werkzeug or uwsgi). This has drawback because production ready server like uwsgi limit the number of thread or process and so this does not scale well to the point we had to [disable it by default](https://bugs.tryton.org/issue7737).  
So we need a solution that is thread-less.

## Proposal

We see two options:

- Adding a separate server which will be thread-less. The first thought is to base it on [asyncio](https://docs.python.org/3.5/library/asyncio.html). So it should be deployed separately and a reverse-proxy should be configured to dispatch the request between the two services.
- Allow to run trytond and replace thread/fork by [greenlet](https://greenlet.readthedocs.io/en/latest/) by using [gevent](http://www.gevent.org/). So a single process could be run for both requests or one thread/fork process can be launched as usual and a second with gevent to process long-polling request (using a reverse-proxy).

The two options are not mutually exclusive but it is probably better to have one way to scale up long-polling.

## Implementation

Here are prototypes of both solution:

- asyncio: [https://codereview.tryton.org/47741003/](https://codereview.tryton.org/47741003/)
- gevent: [https://codereview.tryton.org/53501002](https://codereview.tryton.org/53501002)

_Poll ([view on site](https://discuss.tryton.org/t/thread-less-long-polling/960/1))_

---

<div class="post-metadata">

**Author:** ![edbo](https://discuss-cdn.tryton.org/letter_avatar_proxy/v4/letter/e/f14d63/32.png) [@edbo](https://discuss.tryton.org/u/edbo)\
**Post date:** [December 15, 2018, 11:25am UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/2 "2018-12-15T11:25:02Z")

</div>

asyncio is fully integrated into Python3 and has the Python-like syntax, so it is easier to adapt ([https://www.youtube.com/watch?v=ZzfHjytDceU](https://www.youtube.com/watch?v=ZzfHjytDceU)). Even more, (now I’m going into the dangerzone 🙂) why not use websockets?

---

<div class="post-metadata">

**Author:** ![nicoe](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/nicoe/32/2880_2.png) [@nicoe](https://discuss.tryton.org/u/nicoe)\
**Post date:** [December 15, 2018, 11:52am UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/3 "2018-12-15T11:52:35Z")

</div>

To sum up the discussions we had about this subject yesterday, here’s some points:

- gevent patch is minimal
- gevent can use tryton objects (eg for authentication)
- asyncio is included with python and thus probably more sustainable
- asyncio adds a pure python dependency, gevent is more low-level and thus complicated

> [@edbo](#):
>
> why not use websockets?

The difficulty is implementing them in the GTK client, in sao it wouldn’t be a problem but in tryton it’s another story.

---

<div class="post-metadata">

**Author:** ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)\
**Post date:** [December 15, 2018, 2:19pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/4 "2018-12-15T14:19:13Z")

</div>

> [@edbo](#):
>
> asyncio is fully integrated into Python3 and has the Python-like syntax, so it is easier to adapt

I would say quite this opposite. The introduction of asyncio in Python has split the language into two flavors which can not really cooperate together. It is the main problem to use it with Tryton because almost any existing function/tools can not be reused.

> [@nicoe](#):
>
> asyncio is included with python and thus probably more sustainable

But asyncio is younger 2012 and gevent 2009 and greenlet 2006. gevent and greenlet are currently actively maintained as we can see support for new Python version is added with alpha release.  
Also being in the standard library is nice but it is not necessary always the best tool. For example we use [requests](http://python-requests.org/) in many modules while there are modules in standard library to do the same.

> [@nicoe](#):
>
> asyncio adds a pure python dependency, gevent is more low-level and thus complicated

Except that we would need [aiohttp](https://github.com/aio-libs/aiohttp) (because asyncio is not battery included) which has C and Cython files.

I may sound very negative about asyncio but indeed I think it is a nice addition to Python (but it would have been nicer to stay compatible with existing lib). Indeed it is the trend to use it for everything that is wrong for me. Sequential and multi-thread programming are still relevant in most cases mainly because it is simpler.

> Asynchronous programming is more complex than classical “sequential” programming

from [18.5. asyncio — Asynchronous I/O, event loop, coroutines and tasks — Python 3.6.15 documentation](https://docs.python.org/3.6/library/asyncio.html)

---

<div class="post-metadata">

**Author:** ![nicoe](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/nicoe/32/2880_2.png) [@nicoe](https://discuss.tryton.org/u/nicoe)\
**Post date:** [December 15, 2018, 3:10pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/5 "2018-12-15T15:10:16Z")

</div>

> [@ced](#):
>
> It is the main problem to use it with Tryton because almost any existing function/tools can not be reused.

Even if asyncio was really integrated to python, using it with Tryton wouldn’t be easy.

> [@ced](#):
>
> Except that we would need [aiohttp](https://github.com/aio-libs/aiohttp) (because asyncio is not battery included) which has C and Cython files.

That’s the pure python dependency I talk about. It has indeed Cython files used to parse the HTTP requests.  
Of course YMMV but I find this easier to grasp than a C library fidling with the stack.

> [@ced](#):
>
> For example we use [requests](http://python-requests.org/) in many modules while there are modules in standard library to do the same.

`account_fr_chorus` and `stock_package_shipping_*` are using it. Not that many in fact.  
But I am not against the inclusion of third-party libraries of course, it’s just that it’s nice that asyncio is included with python.

> [@ced](#):
>
> Indeed it is the trend to use it for everything that is wrong for me.

I agree, asyncio should indeed be used for what its name hints it should be used for : IO.  
And that’s the issue here, the bus mainly does IO because there is very few computations (it’s almost a microservice 😛).

> [@ced](#):
>
> > Asynchronous programming is more complex than classical “sequential” programming
> 
> from [18.5. asyncio — Asynchronous I/O, event loop, coroutines and tasks — Python 3.6.15 documentation](https://docs.python.org/3.6/library/asyncio.html)

_Sequential programming_, when talking about concurrent programming I am not sure it’s really more complex.

PS: I did not vote as I don’t have yet an opinion about which solution is better. My biggest fear is that indeed greenlets were cool ten years ago but since then there has been a pradigm switch and I don’t expect it to change any time soon, so I think that it will be less and less used and will slowly become irrelevant.

---

<div class="post-metadata">

**Author:** ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)\
**Post date:** [December 15, 2018, 3:56pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/6 "2018-12-15T15:56:48Z")

</div>

> [@nicoe](#):
>
> And that’s the issue here, the bus mainly does IO because there is very few computations

Not for me, the bus is mainly about waiting. But not waiting the availability of IO resource (aka IO bounds) but that an external event happens. So the goal is to wait by consuming the less resources (DB connections, threads, memory etc.) possible.  
That’s why the asyncio code is indeed very similar to the existing bus code. It is only removing threads and replace them by corouting/greenlet using a different syntax.

---

<div class="post-metadata">

**Author:** ![edbo](https://discuss-cdn.tryton.org/letter_avatar_proxy/v4/letter/e/f14d63/32.png) [@edbo](https://discuss.tryton.org/u/edbo)\
**Post date:** [December 17, 2018, 11:33am UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/7 "2018-12-17T11:33:02Z")

</div>

I think you have to take a step back and look at the reason why the long-polling service was implemented in the first place. So rethinking what the service is doing and why or what is needed. Then you can start looking for implementing it thread-less. Maybe on thread so clients can send each other messages etc?

---

<div class="post-metadata">

**Author:** ![nicoe](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/nicoe/32/2880_2.png) [@nicoe](https://discuss.tryton.org/u/nicoe)\
**Post date:** [December 17, 2018, 12:29pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/8 "2018-12-17T12:29:02Z")

</div>

> [@nicoe](#):
>
> To sum up the discussions we had about this subject yesterday, here’s some points:
> 
> - gevent patch is minimal
> - gevent can use tryton objects (eg for authentication)
> - asyncio is included with python and thus probably more sustainable
> - asyncio adds a pure python dependency, gevent is more low-level and thus complicated

I forgot one point:

- asyncio requires a proxy (Tryton is commonly deployed behind a proxy so it’s a bit a non issue but it’s nice to know anyway).

> [@edbo](#):
>
> Maybe on thread so clients can send each other messages etc?

I might not have understood you but implementing the message passing (aka chat) between clients is indeed a use case we have in mind (but it’s not the only one).

Yet for now we can do it using the long-polling solution (@ced will tell you that anyway with HTTP/2 websockets will not be supported anymore) **and** the GTK client does not support them (aiohttp do support websockets for the client side so it could be a start but it’s a big amount of work anyway).

---

<div class="post-metadata">

**Author:** ![pokoli](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/pokoli/32/22_2.png) [@pokoli](https://discuss.tryton.org/u/pokoli)\
**Post date:** [December 17, 2018, 3:30pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/9 "2018-12-17T15:30:35Z")

</div>

I’ve just voted greenlet because (correct me if I’m wrong) using it will also improve the other trytond requests (not only the bus one’s). Also I find it’s patch simplier which will ease the maintenance.

Just on doubt here: Do you plan to add those dependencies as required for all users or use them optionally only for the ones that want to use the long-poling system?

---

<div class="post-metadata">

**Author:** ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)\
**Post date:** [December 17, 2018, 3:38pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/10 "2018-12-17T15:38:37Z")

</div>

> [@pokoli](#):
>
> it will also improve the other trytond requests

Such “coroutined” tryton could also answer to standard request. I do not know if it improves the performance or not. Indeed I think it depends on the use case.

> [@pokoli](#):
>
> Do you plan to add those dependencies as required for all users or use them optionally only for the ones that want to use the long-poling system?

You can see the [patch](https://codereview.tryton.org/53501002) which I polished to be ready for inclusion. It adds only optional dependencies and it is even not required to run the bus.

---

<div class="post-metadata">

**Author:** ![nicoe](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/nicoe/32/2880_2.png) [@nicoe](https://discuss.tryton.org/u/nicoe)\
**Post date:** [December 17, 2018, 3:46pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/11 "2018-12-17T15:46:30Z")

</div>

> [@pokoli](#):
>
> I’ve just voted greenlet because (correct me if I’m wrong) using it will also improve the other trytond requests (not only the bus one’s).

I don’t think it will change anything wrt to the performances of other requests (at most it will add some overhead to the monkey patched calls).

---

<div class="post-metadata">

**Author:** ![nicoe](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/nicoe/32/2880_2.png) [@nicoe](https://discuss.tryton.org/u/nicoe)\
**Post date:** [December 17, 2018, 4:11pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/12 "2018-12-17T16:11:58Z")

</div>

> [@pokoli](#):
>
> Just on doubt here: Do you plan to add those dependencies as required for all users or use them optionally only for the ones that want to use the long-poling system?

Indeed the patches are not includable as is.  
I think we will need to use [conditional dependencies](https://hynek.me/articles/conditional-python-dependencies/).

---

<div class="post-metadata">

**Author:** ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)\
**Post date:** [December 17, 2018, 4:33pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/13 "2018-12-17T16:33:00Z")

</div>

> [@ced](#):
>
> You can see the [patch](https://codereview.tryton.org/53501002) which I polished to be ready for inclusion.

Oops, the review stayed on my laptop. It is updated now.

> [@ced](#):
>
> Such “coroutined” tryton could also answer to standard request. I do not know if it improves the performance or not. Indeed I think it depends on the use case.

There may be some drawbacks to use coroutine with psycopg2: [http://initd.org/psycopg/docs/advanced.html#support-for-coroutine-libraries](http://initd.org/psycopg/docs/advanced.html#support-for-coroutine-libraries)

---

<div class="post-metadata">

**Author:** ![nicoe](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/nicoe/32/2880_2.png) [@nicoe](https://discuss.tryton.org/u/nicoe)\
**Post date:** [December 17, 2018, 4:52pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/14 "2018-12-17T16:52:54Z")

</div>

> [@pokoli](#):
>
> Also I find it’s patch simplier which will ease the maintenance.

My gut feeling is that this simplicity hides (too much to my liking) real complexity.

For our use case, it’s not an issue given that the bus is fairly simple. But if I had to write a complete asynchronous application from scratch I would probably use asyncio instead of gevent (I really like the explicit nature of `async` / `await`, the main issue is the incompatibilities between the libraries).

---

<div class="post-metadata">

**Author:** ![parviz](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/parviz/32/1274_2.png) [@parviz](https://discuss.tryton.org/u/parviz)\
**Post date:** [December 17, 2018, 4:53pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/15 "2018-12-17T16:53:47Z")

</div>

HI All…  
I think asyncio Its impact on your code is very invasive and it is insufficiently integrated into the programming language and runtime. The later makes diagnosing problems more difficult due to insufficient help from tools like debuggers…  
I think too gevent is much more intuitive to use, and faster…

---

<div class="post-metadata">

**Author:** ![pokoli](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/pokoli/32/22_2.png) [@pokoli](https://discuss.tryton.org/u/pokoli)\
**Post date:** [December 17, 2018, 6:57pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/16 "2018-12-17T18:57:06Z")

</div>

> [@nicoe](#):
>
> But if I had to write a complete asynchronous application from scratch I would probably use asyncio instead of gevent (I really like the explicit nature of `async` / `await` , the main issue is the incompatibilities between the libraries).

But we are not an asynchronous application but a synchronous one with one asynchronous functionality (the bus message).

---

<div class="post-metadata">

**Author:** ![nicoe](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/nicoe/32/2880_2.png) [@nicoe](https://discuss.tryton.org/u/nicoe)\
**Post date:** [December 17, 2018, 9:39pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/17 "2018-12-17T21:39:39Z")

</div>

> [@pokoli](#):
>
> But we are not an asynchronous application but a synchronous one with one asynchronous functionality (the bus message).

Indeed, I just said that for our use case it’s not an issue. Yet **if** I had to write something from scratch I wouldn’t use gevent.

---

<div class="post-metadata">

**Author:** ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)\
**Post date:** [December 23, 2018, 12:55am UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/18 "2018-12-23T00:55:14Z")

</div>

FYI, I submitted [Allow to redirect bus request (#7943) · Issues · Tryton / Tryton · GitLab](https://bugs.tryton.org/issue7943) to ease to add a separate server for long polling (no matter the thread-less solution chosen).

---

<div class="post-metadata">

**Author:** ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)\
**Post date:** [March 18, 2019, 5:00pm UTC](https://discuss.tryton.org/t/thread-less-long-polling/960/19 "2019-03-18T17:00:09Z")

</div>

This topic was automatically closed after 6 days. New replies are no longer allowed.
