Пытаюсь запустить задачу в отдельном потоке на 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-файл в новом потоке, и получил тот же результат. Никаких ошибок или чего-либо еще, просто после этой точки ничего не запускалось. Я перенес код, который читает и декодирует файл, в представление в главном потоке, а затем просто передал извлеченные данные в новый поток, и после этого все работало отлично.