2

I wish to run a long-running script in the background upon receiving a request. I read about subprocess but I require that the call is nonblocking so that the request can complete in time.

def controlCrawlers(request):

    if request.method == 'POST' and 'type' in request.POST and 'cc' in request.POST:

        if request.POST['type'] == '3':
            if request.POST['cc'] == '1':
                    try: #temp solution checking socket is occupied by trying to connect
                        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                        s.connect(('localhost',DISCOVERY_SOCKET))
                        s.close()

                        return HttpResponse(simplejson.dumps({'success':0,'message': 'Socket is occupied. Possible crawler is already running'}), \
                                        mimetype='application/json')
                    except:
                        pid = os.fork()

                        if pid == 0:
                            #f = open('/home/foo/django','a')
                            #f.write('abc')
                           # f.close()
                            path = os.path.join(os.path.dirname(__file__), 'blogcontentReader/blogpost_crawler.py')
                            os.system("python %s" %path)
                            os._exit(0)

                        return HttpResponse(simplejson.dumps({'success':1,'message': 'Running...'}), \
                                    mimetype='application/json')

I used os.fork as suggested from another post but apparently control does not flow into my if pid == 0 portion. Is this the correct method to do this?

Community
  • 1
  • 1
goh
  • 27,631
  • 28
  • 89
  • 151
  • Try `if request.method == 'POST' and request.POST.get('type') == '3' and request.POST.get('cc') == '1':` and save yourself two indentation levels. Also, since you're returning in `try`, just do `except: pass` and move that stuff out an indentation level too. It will make everything easier to read. – agf Aug 11 '11 at 04:12
  • I'm not sure why `subprocess.Popen` won't work. It doesn't stop execution from continuing? – agf Aug 11 '11 at 04:21
  • @agf , yea, from what i see from the link in my post, it blocks until execution of the child process is complete. – goh Aug 11 '11 at 05:52
  • Are you on OSX? That post is specifically about problems on OSX. – agf Aug 11 '11 at 06:24

2 Answers2

5

Yeah, don't do this, use celery instead. It makes running asynchronous tasks a lot easier, more reliable.

madth3
  • 7,275
  • 12
  • 50
  • 74
Zach Kelling
  • 52,505
  • 13
  • 109
  • 108
  • 1
    @amateur You could always consider it a good learning task as you'll probably want to use it again in another project? – James Khoury Aug 11 '11 at 04:03
  • hmm u guys are probably right. I should consider picking up celery. – goh Aug 11 '11 at 04:07
  • Yes. If you don't want to setup a broker you can use your database as a backend: http://docs.celeryproject.org/en/latest/tutorials/otherqueues.html#django-database – Zach Kelling Aug 11 '11 at 04:09
  • @goh, python-rq(http://python-rq.org/) is also an option. It's a bit easier to start with. – Artem Mezhenin Jun 24 '13 at 17:43
  • The question asked how to Fork a process safely. It doesn't matter if this 'isn't generally done' with django. Sometimes people's requirements live outside of that is considered best practice. –  Jun 27 '17 at 12:27
1

If you don't want to use asynchronous task queues with something like celery you can always just run a python script via cron. There are several options to do this. An example:

  • create a model which save the values which are needed by your process
  • write a standalone python/django script which get the values from the model, executee the task and remove the database entries
  • set up a cronjob to run your script
Torsten Engelbrecht
  • 13,318
  • 4
  • 46
  • 48