mod_wsgi: WSGI error - Resource temporarily unavailable, HTTP status 503

Hello! We are having problems with our service. The message is “Resource temporarily unavailable, 503”. We have an application in Python e Django.

We update the server instance on AWS. The current server is configured as follows:

  • Server version: Apache/2.4.27 (Ubuntu)
  • mod_wsgi 4.5.17
  • Python 3.6
  • Django 1.11.5

CPU and Memory aren’t overloaded.

Instance EC2:

  • t2.medium (2 core, 4 gb RAM)
  • CPU Average: < 20%
  • RAM Used Average: ~200MB

Instância RDS:

  • PostgreSQL 9.5.4
  • t2.small (1 core, 2 gb RAM)
  • CPU Average: < 40%
  • RAM Used Average: ~500MB

We’ve tried all configurations mentioned in the topic: https://github.com/GrahamDumpleton/mod_wsgi/issues/181

WSGIDaemonProcess trac processes=6 threads=1 restart-interval=1500 response-socket-timeout=7 display-name=%{GROUP}

Even we update all settings mentioned in the topic and others topics as: https://groups.google.com/forum/#!topic/modwsgi/-kPH_mwyilw

request-timeout=10

The error persists. All attempts without success.

I get this in the error.log:

[wsgi:error] [pid 21399:tid 140274344871680] (11)Resource temporarily unavailable: [client 172.68.27.190:18983] mod_wsgi (pid=21399): Unable to connect to WSGI daemon process ‘site’ on ‘/var/run/wsgi.21137.0.1.sock’ after multiple attempts as listener backlog limit was exceeded.

Can you help us?

Our current Virtual Host File

<VirtualHost *:443>
        ServerName my.site.com

        DocumentRoot /var/www/site

        ErrorLog ${APACHE_LOG_DIR}/error-site-ssl.log
        CustomLog ${APACHE_LOG_DIR}/access-site-ssl.log combined

        WSGIScriptAlias / /var/www/site/myapp/myapp/wsgi.py
        WSGIDaemonProcess site python-path=/var/www/site:/var/www/site/env/lib/python3.6/site-packages home=/var/www/site request-timeout=10  
        WSGIProcessGroup site
        WSGIApplicationGroup %{GLOBAL}

        WSGIPassAuthorization On

        SSLEngine on
        SSLCertificateFile /etc/apache2/certificates/mysite.pem
        SSLCertificateKeyFile /etc/apache2/certificates/mysite.key
</VirtualHost>

/etc/apache2/apache2.conf

...
WSGISocketPrefix /var/run/wsgi

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 2
  • Comments: 24 (12 by maintainers)

Most upvoted comments

Although WSGI is synchronous and not even driven, that doesn’t mean only one request can run at a time. You still have multiple threads in a process and so you can still have concurrent requests running.

Multithreading only becomes an issue if your application code is heavily CPU intensive, causing contention issues with the Python global interpreter lock.

Another problem you can have is poor design of your code in that you use thread mutex locks to block large sections of code so only one thread can run in that code at the same time. If this is done poorly then multithreading isn’t as effective.

Finally, you could just be trying to handle too much in one process or host and so should if host still has resources, spread across multiple processes, or if host overloaded, use multiple hosts.

Go watch:

where I explain these sorts of issues.

Changing the WSGI server will not necessarily change anything if you have a problem in your code. If you aren’t seeing a specific point where things are blocking, it could well be that your code is running, but looping and not returning.

Try adding instead the following code to your wsgi.py file. This will try and identify which URLs are causing long running requests by monitoring them to completion. This will help to confirm whether this is the issue or not. The statistics output can also be used to track capacity utilisation as another way of tracking it.

So try that and see if you do have long running requests and then can dig more into some of the statistics it generates.

import time
import threading
import os
import mod_wsgi

current_requests = {}

def event_handler(name, **kwargs):
    if name == 'request_started':
        environ = kwargs['request_environ']

        request_data = mod_wsgi.request_data()
        request_data['environ'] = environ
        request_data['tracked'] = False

        request_id = environ['mod_wsgi.request_id']

        current_requests[request_id] = (environ, kwargs, request_data)

    elif name == 'request_finished':
        request_data = mod_wsgi.request_data()
        environ = request_data['environ']
        request_id = environ['mod_wsgi.request_id']
        del current_requests[request_id]

        if request_data['tracked']:
            print('FINISHED %s %s %s' % (request_id, kwargs['application_time'], environ['REQUEST_URI']))

mod_wsgi.subscribe_events(event_handler)

last_metrics = None

def monitor(*args):
    global last_metrics

    while True:
        current_metrics = mod_wsgi.process_metrics()

        if last_metrics is not None:
            cpu_user_time = (current_metrics['cpu_user_time'] -
                    last_metrics['cpu_user_time'])
            cpu_system_time = (current_metrics['cpu_system_time'] -
                    last_metrics['cpu_system_time'])

            request_busy_time = (current_metrics['request_busy_time'] -
                    last_metrics['request_busy_time'])

            request_threads = current_metrics['request_threads']

            # report data

            item = {}
            item['time'] = time.time()
            item['measurement'] = 'process'
            item['process_group'] = mod_wsgi.process_group
            item['process_id'] = os.getpid()

            fields = {}

            fields['cpu_user_time'] = cpu_user_time
            fields['cpu_system_time'] = cpu_system_time

            fields['request_busy_time'] = request_busy_time
            fields['request_busy_usage'] = (request_busy_time /
                    mod_wsgi.threads_per_process)

            fields['threads_per_process'] = mod_wsgi.threads_per_process
            fields['request_threads'] = request_threads

            item['fields'] = fields

            now = time.time()

            header = False
            for request_id, (environ, kwargs, request_data) in list(current_requests.items()):
                running_duration = now - kwargs['application_start']
                # Dump data for requests running longer than 2.0 seconds.
                if running_duration > 2.0:
                    if not header:
                        print('STATISTICS', item)
                        header = True
                    request_data['tracked'] = True
                    print('RUNNING %s %s %s' % (request_id, running_duration, environ['REQUEST_URI']))

        last_metrics = current_metrics

        current_time = current_metrics['current_time']
        delay = max(0, (current_time + 1.0) - time.time())
        time.sleep(delay)

thread = threading.Thread(target=monitor)
thread.setDaemon(True)
thread.start()