我正在尝试在应用程序与端口绑定之后执行任务,以免它因启动时间太长而被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)