Dear Adler,

Thanks again for sharing your code with us.

Do you think it would be possible to use asyncio to defer the computation of the active connections from the view or middleware ?


Best regards,

Etienne

Le 2017-12-08 à 11:19, Adler Neves a écrit :
forgot mentioning:
the number of active requests is given by "Threads busy" progress bar and in "Busy threads" line of the table of the previous reply.

Em sexta-feira, 8 de dezembro de 2017 14:07:42 UTC-2, Adler Neves escreveu:

    Hello again, Etienne!

    The way you coded that, you are counting how many requests the
    server has replied before your request has been processed.

    A bit differently than you, I implemented it as a view (which is
    not hard to convert into middleware component) that uses
    bootstrap, so some small changes are needed.

    Let me paste some code from my *views.py*:
    """
    import json
    from urllib.request import urlopen

    class ServerStatsView(TemplateView):
        template_name = 'server-stats.html'
        def get(self, request):
            stats =
    json.loads(ServerStatsJsonGetter(request).content.decode())
            processed_stats = dict()
            processed_stats['workers_total'] = 0
            processed_stats['workers_busy'] = 0
            processed_stats['workers_accepting_connections'] = 0
            processed_stats['threads_total'] = 0
            processed_stats['threads_busy'] = 0
            processed_stats['requests_processed'] = 0
            processed_stats['requests_processing'] = 0
            for worker in stats['workers']:
                processed_stats['workers_total']+=1
                processed_stats['workers_accepting_connections']+=
    int(bool(worker['accepting']))
               
    processed_stats['workers_busy']+=int(worker['status']=='busy')
                for thread in worker['cores']:
                    processed_stats['threads_total']+=1
                   
    processed_stats['threads_busy']+=int(bool(thread['in_request']))
                processed_stats['requests_processed']+=worker['requests']
           
    processed_stats['requests_processing']=processed_stats['threads_busy']
            processed_stats['workers_busy_pct'] =
    100*processed_stats['workers_busy']/processed_stats['workers_total']
            processed_stats['workers_avail_pct'] =
    
100*processed_stats['workers_accepting_connections']/processed_stats['workers_total']
            processed_stats['threads_busy_pct'] =
    100*processed_stats['threads_busy']/processed_stats['threads_total']
            return render(request, self.template_name, {
                'stats':processed_stats,
            })

    def ServerStatsJsonGetter(request):
        with urlopen('http://127.0.0.1:14549
    <http://127.0.0.1:14549>') as urlstream:
            return HttpResponse(
                json.dumps(
                    json.loads(urlstream.read().decode()),
                    indent=4
                ),
                content_type='application/json'
            )
    """

    and now the template *server-stats.html*:
    """
    {% extends "base.html" %}
    {% load i18n %}

    {% block content %}
    <h5>
        {% trans "Workers available for new connections" %}
    </h5>
    <div class="progress">
         <div class="progress-bar" role="progressbar" style="width:
    {{stats.workers_avail_pct}}%"
    aria-valuenow="{{stats.workers_accepting_connections}}"
    aria-valuemax="{{stats.workers_total}}" aria-valuemin="0">
             {{stats.workers_accepting_connections}}
             {% trans "of" %}
             {{stats.workers_total}}
         </div>
    </div>
    <hr>
    <h5>
        {% trans "Workers busy" %}
    </h5>
    <div class="progress">
         <div class="progress-bar" role="progressbar" style="width:
    {{stats.workers_busy_pct}}%"
    aria-valuenow="{{stats.workers_busy}}"
    aria-valuemax="{{stats.workers_total}}" aria-valuemin="0">
             {{stats.workers_busy}}
             {% trans "of" %}
             {{stats.workers_total}}
         </div>
    </div>
    <hr>
    <h5>
        {% trans "Threads busy" %}
    </h5>
    <div class="progress">
         <div class="progress-bar" role="progressbar" style="width:
    {{stats.threads_busy_pct}}%"
    aria-valuenow="{{stats.threads_busy}}"
    aria-valuemax="{{stats.threads_total}}" aria-valuemin="0">
             {{stats.threads_busy}}
             {% trans "of" %}
             {{stats.threads_total}}
         </div>
    </div>
    <hr>
    <h5>
        Table
    </h5>
    <div>
        <table class="table">
            <thead>
                <tr>
                    <th>Aspect</th>
                    <th>Count</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>
                        {% trans "Total workers" %}
                    </td>
                    <td>
                        {{stats.workers_total}}
                    </td>
                </tr>
                <tr>
                    <td>
                        {% trans "Busy workers" %}
                    </td>
                    <td>
                        {{stats.workers_busy}}
                    </td>
                </tr>
                <tr>
                    <td>
                        {% trans "Workers accepting connections" %}
                    </td>
                    <td>
                        {{stats.workers_accepting_connections}}
                    </td>
                </tr>
                <tr>
                    <td>
                        {% trans "Total threads" %}
                    </td>
                    <td>
                        {{stats.threads_total}}
                    </td>
                </tr>
                <tr>
                    <td>
                        {% trans "Busy threads" %}
                    </td>
                    <td>
                        {{stats.threads_busy}}
                    </td>
                </tr>
                <tr>
                    <td>
                        {% trans "Total processed requests" %}
                    </td>
                    <td>
                        {{stats.requests_processed}}
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
    {% endblock content %}
    """

    A request dispatched while ApacheBench was generating some load
    (concurrency = 15) into the server rendered the image you can find
    attached to this message.

    Sincerely,
    Adler

    Em sexta-feira, 8 de dezembro de 2017 10:09:41 UTC-2, Etienne
    Robillard escreveu:

        Hi Ádler,

        Thank you for your reply.

        Can you please review this code before I commit?


        """uWSGIController API Version 0.8.3

        Middleware for storing uWSGI statistics into the environ object.
        """

        import sys
        import os
        import logging
        import demjson
        import urllib

        logger = logging.getLogger(__name__)

        from notmm.controllers.wsgi import WSGIController

        __all__ = ('uWSGIController',)


        class uWSGIController(WSGIController):

            def __init__(self, wsgi_app,
        stats_url='http://localhost:9001 <http://localhost:9001>'):

                self.wsgi_app = wsgi_app
                self.stats_url = stats_url
                super(uWSGIController, self).__init__() # hack

            def init_request(self, request):
                logger.debug('In uWSGIController.init_request...')
                request.environ['uwsgi.requests'] =
        self.connections(self.stats_url)
                self._request = request
                self._environ = request.environ
                return self._request

            def connections(self, url):
                """Return the amount of live connections (requests)
        for all workers"""
                fp = urllib.urlopen(url)
                json = demjson.decode(fp.read())

                connections = 0

                for worker in json['workers']:
                    connections += worker['requests']

                fp.close()

                return connections


        Best regards,

        Etienne


        Le 2017-12-07 à 13:29, Ádler Oliveira Silva Neves a écrit :

        Sounds like you want retrieving statistics from uWSGI's stats
        server.

        http://uwsgi-docs.readthedocs.io/en/latest/StatsServer.html
        <http://uwsgi-docs.readthedocs.io/en/latest/StatsServer.html>

        In order to get that JSON via HTTP requests, your server
        ".ini" should receive extra arguments to start an stats
        server listening to the specified port and application must
        be somehow aware of such port number, which has a side-effect
        of increasing coupling.

        Sincerely,

        Adler

        On 07/12/2017 13:13, Etienne Robillard wrote:
        Hi,

        I would like to access the uWSGI stats API from within
        Django by creating a custom WSGI middleware.

        Could it be possible to compute the number of requests
        currently being used by uWSGI workers in Python/Django ?

        Ideally, i could then retrieve the active connections in use
        in a standard Django view:

        def someview(request):

            # retrieve the number of active requests (connections)

            connections = request.environ['uwsgi.requests']


        What do you think?


        Etienne



-- You received this message because you are subscribed to the
        Google Groups "Django users" group.
        To unsubscribe from this group and stop receiving emails from
        it, send an email to django-users...@googlegroups.com.
        To post to this group, send email to django...@googlegroups.com.
        Visit this group at
        https://groups.google.com/group/django-users
        <https://groups.google.com/group/django-users>.
        To view this discussion on the web visit
        
https://groups.google.com/d/msgid/django-users/c6d79973-28b8-5236-a64e-4c24ed3c30a7%40gmail.com
        
<https://groups.google.com/d/msgid/django-users/c6d79973-28b8-5236-a64e-4c24ed3c30a7%40gmail.com?utm_medium=email&utm_source=footer>.
        For more options, visit https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>.

-- Etienne Robillard
        tka...@yandex.com
        https://www.isotopesoftware.ca/ <https://www.isotopesoftware.ca/>

--
You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com <mailto:django-users+unsubscr...@googlegroups.com>. To post to this group, send email to django-users@googlegroups.com <mailto:django-users@googlegroups.com>.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/c7a78364-e980-4144-ac1e-d0601a1de51c%40googlegroups.com <https://groups.google.com/d/msgid/django-users/c7a78364-e980-4144-ac1e-d0601a1de51c%40googlegroups.com?utm_medium=email&utm_source=footer>.
For more options, visit https://groups.google.com/d/optout.

--
Etienne Robillard
tkad...@yandex.com
https://www.isotopesoftware.ca/

--
You received this message because you are subscribed to the Google Groups "Django 
users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/2c959c23-13ad-869f-b40e-2cae40515180%40yandex.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to