The short answer is that code will not work with the version of mod_wsgi you 
are using. It will not kill the forked process properly and would actually kill 
the WSGI application daemon process instead, leaving the forked process still 
running and thus why it consumed memory. That it was killing the WSGI 
application daemon process would have been evident in the error logs which is 
why I asked about logs.

Some extra tricks were required with a special directive needing to be given to 
mod_wsgi for the version you are using to allow signal handlers to be 
overridden and the forked process would need to reset the signal handlers 
before running the job.

Since it was a pain to have to use the fiddles I worked out a way in mod_wsgi 
to avoid needing to do all that. You will need to upgrade to the latest 
mod_wsgi version though, which is 4.4.9.

That isn't all that is required though as that code doesn't properly wait on 
the process when terminating it. This will result in a zombie process hanging 
around, which isn't a good idea. In worst case, since terminate() only tries 
SIGTERM, it may not go away.

Now you can't simply go run 'pip install -U mod_wsgi' because of the issue we 
had with that breaking the mod_wsgi-httpd install. That issue has also now been 
fixed though. What you therefore want to do is reinstall both mod_wsgi-httpd 
and mod_wsgi.

So if I got it right, you should be able to do.

pip2.7 -v -v -v --log $HOME/pip.log install -U --user --build $HOME/tmp/pip 
mod_wsgi-httpd
pip2.7 install -U --user mod_wsgi

I am hoping that doesn't effect your running site. To be safe you may want to 
shut it down when doing the update.

Once upgraded, use the following code. Remove print statements when happy. I 
would get rid of the force_kill flag as you probably always want to be force 
killing it and escalating that to SIGKILL to definitely get rid of it.

import multiprocessing
import signal
import time
import os

class TimeoutException(Exception):
    pass

class RunableProcessing(multiprocessing.Process):
    def __init__(self, func, *args, **kwargs):
        self.queue = multiprocessing.Queue(maxsize=1)
        args = (func,) + args
        multiprocessing.Process.__init__(self, target=self.run_func, args=args, 
kwargs=kwargs)

    def run_func(self, func, *args, **kwargs):
        try:
            result = func(*args, **kwargs)
            self.queue.put((True, result))
        except Exception as e:
            self.queue.put((False, e))

    def done(self):
        return self.queue.full()

    def result(self):
        return self.queue.get()

def timeout(seconds, force_kill=True):
    def wrapper(function):
        def inner(*args, **kwargs):
            now = time.time()
            proc = RunableProcessing(function, *args, **kwargs)
            proc.start()
            proc.join(seconds)
            if proc.is_alive():
                print 'still alive'
                if force_kill:
                    print 'kill it'
                    proc.terminate()
                    proc.join(3)
                    print 'is it dead', proc.is_alive()
                    if proc.is_alive():
                        try:
                            print 'force kill'
                            os.kill(proc.pid, signal.SIGKILL)
                        except Exception:
                            pass
                        proc.join(1)
                        print 'alive', proc.is_alive()
                runtime = int(time.time() - now)
                raise TimeoutException('timed out after {0} 
seconds'.format(runtime))
            assert proc.done()
            success, result = proc.result()
            if success:
                return result
            else:
                raise result
        return inner
    return wrapper

def term(*args):
    print 'term'
    time.sleep(4.0)
    print 'done'

@timeout(5.0)
def func():
    signal.signal(signal.SIGTERM, term)
    print 'sleep'
    time.sleep(10)

def application(environ, start_response):
    status = '200 OK'
    output = b'Hello World!'

    func()

    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]

On 21/02/2015, at 10:23 PM, Paul Royik <[email protected]> wrote:

> I used this code:
> class TimeoutException(Exception):
>     pass
> 
> 
> class RunableProcessing(multiprocessing.Process):
>     def __init__(self, func, *args, **kwargs):
>         self.queue = multiprocessing.Queue(maxsize=1)
>         args = (func,) + args
>         multiprocessing.Process.__init__(self, target=self.run_func, 
> args=args, kwargs=kwargs)
> 
>     def run_func(self, func, *args, **kwargs):
>         try:
>             result = func(*args, **kwargs)
>             self.queue.put((True, result))
>         except Exception as e:
>             self.queue.put((False, e))
> 
>     def done(self):
>         return self.queue.full()
> 
>     def result(self):
>         return self.queue.get()
> 
> 
> def timeout(seconds, force_kill=True):
>     def wrapper(function):
>         def inner(*args, **kwargs):
>             now = time.time()
>             proc = RunableProcessing(function, *args, **kwargs)
>             proc.start()
>             proc.join(seconds)
>             if proc.is_alive():
>                 if force_kill:
>                     proc.terminate()
>                 runtime = int(time.time() - now)
>                 raise TimeoutException('timed out after {0} 
> seconds'.format(runtime))
>             assert proc.done()
>             success, result = proc.result()
>             if success:
>                 return result
>             else:
>                 raise result
>         return inner
>     return wrapper
> 
> There was nothing suspicious in error logs, just request-timeout from tme to 
> time.
> 
> On Saturday, February 21, 2015 at 11:44:29 AM UTC+2, Graham Dumpleton wrote:
> On 21/02/2015, at 8:04 PM, Paul Royik <[email protected]> wrote:
> 
>> First of all I found a post, where you said, that it is not a good idea to 
>> use multiprocessing with mod_wsgi.
>> Secondly, library that I use is not very compatible with multiprocessing 
>> (pickling issues).
> 
> If using a queue, the only data that should need pickling is the response 
> data. If the classes from your library can not be pickled all you need to do 
> is convert them to more basic data structures so they can be returned. Since 
> you are likely going to have to convert the result into something that can be 
> rendered into your page response if embedding results in a web page, you 
> could even render the page in the separate process and just return the text 
> of the page to then be returned from the web request.
> 
>> Thirdly, very fust memory overflow, in 20 minutes memory usage grows to 7 GB.
> 
> So it sounds like you didn't really understand why it failed.
> 
> Was there anything strange in the way of messages in the Apache error log?
> 
> What was the actual code you were using with the multiprocess module?
> 
> That is which of the techniques from:
> 
> https://docs.python.org/2/library/multiprocessing.html
> 
> were you using, but then also how did you modify those to accommodate trying 
> to kill the process when your timeout was reached and also ensure that the 
> child process was properly reaped and didn't just hang around as a zombie 
> process?
> 
> Graham
> 
>> On Saturday, February 21, 2015 at 9:23:18 AM UTC+2, Graham Dumpleton wrote:
>> 
>> On 21/02/2015, at 9:52 AM, Paul Royik <[email protected]> wrote: 
>> 
>> > Hello. 
>> > Is there anyway to stop thread using subprocess module. 
>> 
>> The subprocess module has got nothing to do with in process threading. 
>> 
>> > As far as I know multiprocessing is not applicable for mod_wsgi. 
>> 
>> Explain what the problem was when you attempted to use the multiprocessing 
>> module. 
>> 
>> I occasionally have seen people say that multiprocessing doesn't work under 
>> mod_wsgi. I have never actually ever had some one lodge a bug report 
>> indicating what the problem is, nor even use the mailing list to explain 
>> what they were doing with a very simple code example, and explain what 
>> didn't work. 
>> 
>> > I returned to thread solution, because there is no other way to stop 
>> > function. 
>> 
>> If you couldn't get the timeout based method within the algorithm self 
>> checking, it will not work if in a thread. 
>> 
>> Ultimately, you should not even be attempting to do what you are in the web 
>> server processes, or even as sub processes of the web application. What 
>> would be regarded as best practice for this sort of thing is a separate task 
>> queueing service which has the capabilities for using separate processes for 
>> task execution and a supervisor system that can kill processes after running 
>> for a set time and not completing. Such a system can also control the rate 
>> at which parallel tasks are allowed to run to control memory usage. 
>> 
>> Now before you jump up and down and say 'how, how, how', explain what you 
>> were trying to do with multiprocessing and how it failed. 
>> 
>> Graham 
>> 
>> 
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "modwsgi" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected].
>> To post to this group, send email to [email protected].
>> Visit this group at http://groups.google.com/group/modwsgi.
>> For more options, visit https://groups.google.com/d/optout.
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "modwsgi" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/modwsgi.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"modwsgi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/modwsgi.
For more options, visit https://groups.google.com/d/optout.

Reply via email to