Удалось разобраться в проблеме. Может быть кому-нибудь поможет.
Дело в том, что родительский процесс ждет завершения дочернего ( код возврата ).
Я думал, что вызова os._exit() достаточно и это можно увидеть запустив strace:
16059 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=16060, si_status=0, si_utime=0, si_stime=0} ---
Оказалось, что есть нюансы.
Нюанс заключается в следующем. Для родительского процесса нужно установить обработчик сигнала. Сделать это можно использовав библиотеку signal.
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
Первый аргумент - int'вая константа, а второй - действия для сигнала.
После завершения дочернего процесса он уходит в состоянии зомби ( это нормально ), как было в моем случаем. После установки обработчика начинает работать механизм reaping и OS самостоятельно очищает таблицу процессов.
Кстати, на stackoverflow предложили достаточно хорошее решение.
Идея заключается, в том, чтобы сделать демона, который будет смотреть в очередь задач. При этом веб-сервер будет отвечать 202 кодом. Задачки будут разбираться по мере поступления, а статут задачи всегда можно будет узнать по другому URL.