烧瓶-作业未作为后台进程运行

时间:2018-09-12 20:32:37

标签: python flask flask-sqlalchemy concurrent.futures

我正在尝试运行一个包含以下内容的Flask应用程序:

  1. 即时生成API请求
  2. 将每个请求上传到SQLalchemy数据库
  3. 将作业12作为后台进程运行

为此,我有以下代码:

from flask import Flask
from flask import current_app
import concurrent.futures
from concurrent.futures import ThreadPoolExecutor
import queue

app = Flask(__name__)
q = queue.Queue()

def build_cache(): 
    # 1. Yielding API requests on the fly
    track_and_features = spotify.query_tracks() # <- a generator
    while True:
        q.put(next(track_and_features))


def upload_cache(tracks_and_features):
    # 2. Uploading each request to a `SQLalchemy` database
    with app.app_context():      
        Upload_Tracks(filtered_dataset=track_and_features)

    return "UPLOADING TRACKS TO DATABASE" 


@app.route('/cache')
def cache():
    # 3. Do `1` and `2` as a background process
    with concurrent.futures.ThreadPoolExecutor() as executor:

        future_to_track = {executor.submit(build_cache): 'TRACKER DONE'}

        while future_to_track:
            # check for status of the futures which are currently working
            done, not_done = concurrent.futures.wait(
                                                future_to_track, 
                                                timeout=0.25,
                                                return_when=concurrent.futures.FIRST_COMPLETED) 

            # if there is incoming work, start a new future
            while not q.empty():

                # fetch a track from the queue
                track = q.get()

                # Start the load operation and mark the future with its TRACK
                future_to_track[executor.submit(upload_cache, track)] = track
            # process any completed futures
            for future in done:
                track = future_to_track[future]
                try:
                    data = future.result()
                except Exception as exc:
                    print('%r generated an exception: %s' % (track, exc))

                del future_to_track[future]

    return 'Cacheing playlist in the background...'

以上所有方法均可,但不能作为后台处理。调用cache()时,该应用程序挂起,仅在该过程完成后才恢复运行。

我用gunicorn -c gconfig.py app:app -w 4 --threads 12

运行它

我在做什么错了?


  

编辑:如果为了简化起见,请对其进行调试,并简单地编写:

# 1st background process
def build_cache():
    # only ONE JOB
    tracks_and_features = spotify.query_tracks() # <- not a generator               
    while True:
         print next(tracks_and_features)

# background cache
@app.route('/cache')
def cache():
    executor.submit(build_cache)
    return 'Cacheing playlist in the background...'

该过程在后台运行。

但是,如果我添加另一个作业:

def build_cache():

    tracks_and_features = spotify.query_tracks()
    while True:
        Upload_Tracks(filtered_dataset=next(tracks_and_features) #SQLalchemy db

背景不再起作用。

简而言之:

背景仅在我一次运行一项作业时才起作用(这是首先使用队列的想法的局限性)

似乎不知道该问题是将后台进程绑定到SQLalchemy。在这里完全迷路了。

2 个答案:

答案 0 :(得分:2)

仍然不确定您的意思

  

我的意思是,应用程序等待登录时发出的所有请求,然后才进入主页。它应该立即转到主页,并在后台发出请求

这里有几个问题:

  • 您的队列是进程的全局队列,即每个empicorn工作者只有一个队列;您可能希望将队列绑定到您的请求,以使多个请求不会共享内存中的同一队列。考虑使用context locals
  • 如果UploadTracks正在写入数据库,则表上可能有锁。检查索引并检查数据库中的锁定等待时间。
  • SQLAlchemy可能配置有一个小的connection pool,而第二个UploadTracks正在等待第一个返回其连接。

在您的第一个示例中,端点在等待所有期货完成后才返回,而在您的第二个示例中,端点在将任务提交给执行者后立即返回。如果您希望烧瓶在任务仍在后台线程中运行时快速响应,请删除with concurrent.futures.ThreadPoolExecutor() as executor:并在模块顶部构造一个全局线程池。

上下文管理器使用with等待所有提交的任务,然后退出,但是我不确定这是否是您的主要问题。

答案 1 :(得分:1)

尝试在路由处理程序之外创建Form

ThreadPoolExecutor