Пытаюсь запустить задачу в отдельном потоке на Heroku, но новый поток не открывается

У меня есть приложение Django с представлением в админке, которое позволяет пользователю загрузить csv, который затем передается скрипту, создающему и обновляющему элементы в базе данных на основе этих данных. Представление запускает скрипт в новом потоке и затем возвращает сообщение об успехе "Загрузка началась"

apps/products/admin.py

from threading import Thread
# ...
from apps.products.scripts import update_products_from_csv

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    # normal ModelAdmin stuff

    def upload_csv(self, request):
        if request.method == 'POST':
            csv_file = request.FILES['csv_file']
            t = Thread(target=update_products_from_csv.run, args=[csv_file])
            t.start()
            messages.success(request, 'Upload started')
            return HttpResponseRedirect(reverse('admin:products_product_changelist'))

apps/products/scripts/update_products_from_csv.py

import csv
import threading
from time import time
# ...

def run(upload_file):
    # print statements just here for debugging

    print('Update script running', threading.currentThread())

    start_time = time()
    print(start_time)

    decoded_file = upload_file.read().decode('utf-8').splitlines()
    csv_data = [d for d in csv.DictReader(decoded_file)]
    print(len(csv_data))

    for i, row in enumerate(csv_data):
        if i % 500 == 0:
            print(i, time() - start_time)
        # code that checks if item needs to be created or updated and logs accordingly

    print('Finished', time() - start_time)

При разработке все работает нормально. Сообщение "Upload started" появляется почти сразу в браузере, а в консоли печатается, что загрузка началась в Thread-3 или Thread-5, или как угодно, а затем выполняются все остальные операторы печати. По окончании я могу запросить модель EntryLog и подтвердить, что она внесла свои изменения.

Когда я продвигаю это на Heroku, я все еще получаю сообщение "Upload started" сразу в браузере, но когда я смотрю логи, он печатает Thread-1 вместо Thread-[любое другое число]. После этого я вижу, как выполняется оператор печати start_time, но после этого начинается ответ, и ни один из других операторов печати не выполняется. Через некоторое время я запрашиваю модель EntryLog, но никаких изменений не произошло.

Из того, что я прочитал, следует, что я должен иметь возможность использовать потоковую передачу на Heroku так же, как и локально, но кажется, что скрипт выполняется в основном потоке, а затем просто тихо убивает его, когда начинается ответ.

Оказалось, что Heroku действительно открывал новый поток. То, что он показывал Thread-1, когда я вызывал print(threading.currentThread()), было красной селедкой. В моей среде разработки (Windows) порожденный поток всегда выводил Thread-[число больше 1], но дальнейшие тесты с простыми потоками, которые, как я был уверен, выполнялись до конца, в среде Heroku всегда выводили Thread-1. Возможно, разница в работе библиотеки в Windows и Linux? (Это был мой первый опыт использования библиотеки потоков, так что прошу прощения, если я упустил что-то очевидное)

Фактически, проблема была в том, где я читал файл csv. Много операторов печати позже я сузил это до точной строки, где все перестало работать. Я попробовал простой тест, просто читая txt-файл в новом потоке, и получил тот же результат. Никаких ошибок или чего-либо еще, просто после этой точки ничего не запускалось. Я перенес код, который читает и декодирует файл, в представление в главном потоке, а затем просто передал извлеченные данные в новый поток, и после этого все работало отлично.

Back to Top