#python #django
Вопрос:
Для начала, я искал это раньше, но мне не повезло найти что-то похожее на это.
Фон:
Я создал приложение для инвентаризации для работы, чтобы помочь моей команде быстро просматривать статистику по нашей ИТ-инфраструктуре. У меня есть потоки, запускаемые при загрузке приложения, чтобы запустить некоторые функции очистки. Этот код отлично работает, но это происходит всякий раз, когда я создаю и применяю миграции баз данных (manage.py совершайте миграции amp; manage.py мигрировать).
Цель:
Я хотел бы запустить код очистки только тогда, когда я выполняю команду runserver (manage.py runserver). Таким образом, у меня нет ресурсов, конкурирующих между деятельностью по миграции и деятельностью по очистке. Это также часто приводит к большому количеству ошибок, потому что иногда не все модели/поля базы данных еще существуют в базе данных.
Идеи:
- Измените код в репозитории django, чтобы ввести флаг, который я затем смогу проверить, прежде чем запускать код очистки. Не рекомендуется, это будет перезаписано при обновлении django, и оно не будет сохраняться между моим сервером разработки и сервером prod.
- Найдите способ проверить, какая команда выполняется с помощью manage.py, и введите проверку, чтобы начать очистку только в том случае, если эта команда запущена. Рекомендуется, чтобы это оставалось в моей кодовой базе и могло легко перемещаться между экземплярами dev и prod.
Я открыт для других идей для достижения этой цели. Если есть другой способ начать очистку при запуске приложения, то это, скорее всего, тоже сработает. Функция apps.ready была единственным, что я смог найти, чтобы запустить что — то при запуске приложения.
Изменить: Вот что находится внутри apps.ready()
функции:
def ready(self):
set_default_database_items()
if environment == "prod":
from .threading.scraping import TimerScrape
from .threading.keep_alive import KeepAliveThread
TimerScrape()
KeepAliveThread(1)
KeepAliveThread(2)
Вот посмотрите на TimerScrape()
нить:
def run(self):
sleep(60)
while True:
idle = True
vcenters = Vcenter.objects.all()
connection.close()
netapps = StorageSystem.objects.all()
connection.close()
rubriks = BackupSystem.objects.all()
connection.close()
current_time = datetime.now(timezone.utc)
# get list of current threading and their names
threads = enumerate()
thread_list = []
for thread in threads:
thread_list.append(thread.name)
# go through each vCenter and start scrape
for vc in vcenters:
thread_name = vc.name "_thread"
if thread_name not in thread_list:
if vc.last_updated is None:
self.vcscrape(vc.name, vc.user, vc.password)
elif vc.last_updated is not None:
time_difference = current_time - vc.last_updated
if time_difference.seconds > 14400:
self.vcscrape(vc.name, vc.user, vc.password)
else:
print("vCenters: Too soon to update vCenter " vc.name)
else:
idle = False
print("vCenter " vc.name " update is in progress")
# go through each NetApp and start scrape
for cluster in netapps:
thread_name = cluster.name "_thread"
if thread_name not in thread_list:
if cluster.last_updated is None:
self.netappscrape(cluster.name, cluster.user, cluster.password)
elif cluster.last_updated is not None:
time_difference = current_time - cluster.last_updated
if time_difference.seconds > 14400:
self.netappscrape(cluster.name, cluster.user, cluster.password)
else:
print("Clusters: Too soon to update Cluster " cluster.name)
else:
idle = False
print("Cluster " cluster.name " update is in progress")
# go through each Rubrik and start scrape
for cluster in rubriks:
thread_name = "backup_" cluster.name "_thread"
if thread_name not in thread_list:
if cluster.last_updated is None:
self.rubrikscrape(cluster.name, cluster.user, cluster.password)
elif cluster.last_updated is not None:
time_difference = current_time - cluster.last_updated
if time_difference.seconds > 14400:
self.rubrikscrape(cluster.name, cluster.user, cluster.password)
else:
print("Backups: Too soon to update Cluster " cluster.name)
else:
idle = False
print("Backups " cluster.name " update is in progress")
if idle:
platforms = Platform.objects.all()
connection.close()
applications = Application.objects.all()
connection.close()
functions = Function.objects.all()
connection.close()
regions = Region.objects.all()
connection.close()
sites = Site.objects.all()
connection.close()
environments = Environment.objects.all()
connection.close()
tag_reports = TagsReport.objects.all()
connection.close()
for obj in platforms:
thread_name = "Tag_report_" "platform_" obj.name "_thread"
if thread_name not in thread_list:
if obj.last_updated is None:
self.tagscrape(obj, "platform")
elif obj.last_updated is not None:
time_difference = current_time - obj.last_updated
if time_difference.seconds > 14400:
self.tagscrape(obj, "platform")
else:
print("Too soon to update platform " obj.name)
for obj in applications:
thread_name = "Tag_report" "application_" obj.name "_thread"
if thread_name not in thread_list:
if obj.last_updated is None:
self.tagscrape(obj, "application")
elif obj.last_updated is not None:
time_difference = current_time - obj.last_updated
if time_difference.seconds > 14400:
self.tagscrape(obj, "application")
else:
print("Too soon to update application " obj.name)
for obj in functions:
thread_name = "Tag_report" "function_" obj.name "_thread"
if thread_name not in thread_list:
if obj.last_updated is None:
self.tagscrape(obj, "function")
elif obj.last_updated is not None:
time_difference = current_time - obj.last_updated
if time_difference.seconds > 14400:
self.tagscrape(obj, "function")
else:
print("Too soon to update function " obj.name)
for obj in regions:
thread_name = "Tag_report" "region_" obj.name "_thread"
if thread_name not in thread_list:
if obj.last_updated is None:
self.tagscrape(obj, "region")
elif obj.last_updated is not None:
time_difference = current_time - obj.last_updated
if time_difference.seconds > 14400:
self.tagscrape(obj, "region")
else:
print("Too soon to update region " obj.name)
for obj in sites:
thread_name = "Tag_report" "site_" obj.name "_thread"
if thread_name not in thread_list:
if obj.last_updated is None:
self.tagscrape(obj, "site")
elif obj.last_updated is not None:
time_difference = current_time - obj.last_updated
if time_difference.seconds > 14400:
self.tagscrape(obj, "site")
else:
print("Too soon to update site " obj.name)
for obj in environments:
thread_name = "Tag_report" "environment_" obj.name "_thread"
if thread_name not in thread_list:
if obj.last_updated is None:
self.tagscrape(obj, "environment")
elif obj.last_updated is not None:
time_difference = current_time - obj.last_updated
if time_difference.seconds > 14400:
self.tagscrape(obj, "environment")
else:
print("Too soon to update environment " obj.name)
for obj in tag_reports:
thread_name = "Missing_tags_report_thread"
if thread_name not in thread_list:
if obj.last_updated is None:
self.missing_tag_scrape(obj)
elif obj.last_updated is not None:
time_difference = current_time - obj.last_updated
if time_difference.seconds > 14400:
self.missing_tag_scrape(obj)
else:
print("Too soon to update missing tags reports")
sleep(900)
Небольшое объяснение. Идея состоит в том, что каждые 15 минут этот поток будет проверять, прошло ли 4 часа с момента последнего зарегистрированного обновления для каждого из этих элементов. Если это так, и для объекта не выполняется поток очистки, он запустит новое задание очистки для обновления информации в базе данных.
Если никаких царапин не происходит, это позволит запустить некоторые отчеты, если с момента последнего запуска прошло 4 часа.
Этот поток является автономным, и, как я уже упоминал ниже в своем ответе, я смог выяснить, что если я установлю 60-секундный таймер сна в начале потока, я смогу избежать возникновения проблем при apps.ready()
загрузке функции при запуске приложения.
Комментарии:
1. Пожалуйста, предоставьте достаточно кода, чтобы другие могли лучше понять или воспроизвести проблему.
Ответ №1:
Тот факт, что вы пытаетесь обойти код, означает, что у вас код не в том месте. Запуск скребка не подходит, apps.ready
потому что вам нужно, чтобы он работал только в некоторых ситуациях, но не в других.
Кроме того, запуск кода очистки, когда вы это делаете ./manage.py runserver
, звучит как плохая идея. Вы должны использовать только runserver
для разработки, а не в качестве реальной веб-службы в производственной среде. Вместо этого вам следует развернуть с помощью реального веб — сервера, такого как Apache или Nginx.
Вы можете запустить код очистки с помощью задания cron или какого-либо другого планировщика. Если запуск этого кода очистки сложен, то сценарий bash или команда управления-отличный способ инкапсулировать то, что необходимо сделать.
Комментарии:
1. Код scaping должен запускаться каждый раз при запуске приложения. Вся идея заключается в том, что если с момента последнего обновления прошло 4 часа, он выходит и обновляет данные. Он построен на чистом python с использованием SDK, идея которого заключается в том, что единственное, что нужно сделать, это запустить приложение, а затем просто оставить его в покое. Я не пытаюсь обойти функцию apps.ready, но, учитывая, как django загружает платформу приложений при выполнении миграции, часть очистки не нужно запускать, так как она будет выполнять только действия с базой данных.
2. @JimmyFort Похоже, что вы используете Django непреднамеренным образом. Продолжение этого пути принесет только боль и страдания. Вы должны использовать его ТОЛЬКО
runserver
в целях разработки. Его НИКОГДА не следует использовать для запуска приложения. Для запуска кода очистки следует использоватьcron
или аналогичный планировщик. Джанго не предназначен для этой задачи.3. @JimmyFort Я предлагаю вам узнать о том, как работает веб — приложение. Я объяснил некоторые из них здесь на очень высоком уровне: обычно вы должны развертывать приложение Django с использованием реального веб-сервера, такого как Apache или Nginx. Если вы не знакомы с ними, сейчас самое подходящее время для обучения. Вы быстро увидите, как вы пытаетесь засунуть круглый колышек в квадратное отверстие.
4. Джанго не выполняет работу хрона. Весь код очистки самодостаточен в своих собственных классах и потоках. Он содержит свои собственные функции планирования и cron. Вся идея заключается в том, что поток запускается при запуске приложения, а затем он запускается сам по себе без дополнительного ввода, необходимого с веб-сервера. Единственное, что достигается с помощью Django, — это просто запуск потока.
5. @Джимми, я думаю, что лучше понимаю, что ты имеешь в виду. Мне все еще кажется, что запуск потоков скребка
apps.ready()
-неправильное решение проблемы. И похоже, что cron-это тоже не совсем то, что вам нужно. Возможно, вам нужен внешний скрипт (bat, ps или sh в зависимости от платформы, на которой он работает), который запускает приложение django и службу скребка.
Ответ №2:
Подумав об этом подробнее, я нашел простое решение, введя таймер сна в начале потока, который управляет функцией очистки. Это позволяет мне запускать команды создания и переноса без немедленного запуска потока очистки.
Я также рассматривал возможность использования Apache с mod_wsgi, однако экземпляры как dev, так и prod работают в Windows, и mod_wsgi испытывает трудности с запуском в Windows без каких-либо манипуляций. В конечном итоге я мог бы перенести это на хост unix, но это потребовало бы некоторых дополнительных усилий, которые я бы предпочел не делать в настоящее время.