Я пытаюсь выполнить задачу после того, как приложение выполнит связывание с портом, чтобы Heroku не убивал его из-за слишком долгого запуска при запуске. Мне известно о существовании before_first_request
, однако я хотел бы, чтобы это действие выполнялось как можно скорее после запуска приложения без запроса.
Я загружаю объект в качестве атрибута объекта приложения(потому что мне нужно обращаться к нему через запросы), и этот объект должен странным образом инициализироваться (он проверяет, существует ли файл, и загружает его, если его нет, а затем выполняет кучу вычислений).
В настоящее время я делаю это следующим образом:
def create_app() -> Flask:
...
with app.app_context():
app.model = RecommenderModel() # This downloads a pretty heavy file if it isn't there
app.model.load_products() # This performs a bunch of calculations
...
return app
Это инициализирует приложение должным образом (как проверено локально), однако Heroku убивает его (Ошибка R10), потому что это занимает слишком много времени.
Есть ли способ сделать это асинхронно? Когда я пытался это сделать, контекст приложения терялся.
Редактировать: Дополнительная информация о том, что я делаю:
Объект RecommenderModel
моделирует логику системы рекомендаций. На данный момент рекомендации основаны на векторном косинусном сходстве. Эти векторы извлекаются с использованием предварительно обученных вложений word2vec (это большой файл, который необходимо загрузить). Преобразование из продуктов в векторы выполняется классом Preprocessor
.
Инициализация модели рекомендации выглядит следующим образом:
class RecommenderModel(object):
def __init__(self) -> None:
self.preproc = Preprocessor()
self.product_vector: dict = {}
def load_products(self) -> None:
for product in Product.get_all():
self.product_vector[product.id] = self.preproc.compute_vector(product)
Инициализация препроцессора выглядит следующим образом:
class Preprocessor(object):
def __init__(self, embeddings: str = embeddings) -> None:
S3.ensure_file(embeddings)
self.vectors = KeyedVectors.load_word2vec_format(embeddings)
Метод S3.ensure_file
в основном проверяет, существует ли файл, и загружает его, если его нет:
class S3(object):
client = boto3.client('s3')
@classmethod
def ensure_file(cls, filepath: str) -> None:
if os.path.exists(filepath):
return
dirname, filename = os.path.split(filepath)
bucket_name = os.environ.get('BUCKET_NAME')
cls.client.download_file(bucket_name, filename, filepath)