Running deferred initialization code and gracefully blocking on requests until initialization is complete

huangapple go评论70阅读模式
英文:

Running deferred initialization code and gracefully blocking on requests until initialization is complete

问题

I would like to set up Flask so that it first sets up the listening socket, then runs some initialization code, then holds all incoming request processing until the initialization is complete. How do I set that up?

我想设置Flask,首先设置监听套接字,然后运行一些初始化代码,然后在初始化完成之前保持所有传入请求的处理。我该如何设置?

My Flask app takes about 30s of initialization (loading AI models, etc.). These are required for all real endpoints. However, during development, it is frustrating having to wait and watch for this to complete, before beginning with frontend interactions.

我的Flask应用需要大约30秒的初始化时间(加载AI模型等)。这对于所有真实的端点都是必需的。然而,在开发过程中,不得不等待并观察它完成,然后才能开始与前端的交互,这让人感到沮丧。

I remember old Tomcats (~15 years ago, haven't used it since) having this exact behavior: you could already send a request from an early stage of initialization, and then it would keep the connection open and process and send the response as soon as the webapp was fully loaded.

我记得旧版的Tomcat(大约15年前,之后没有使用过)有这种确切的行为:你可以在初始化的早期阶段就发送请求,然后它会保持连接打开并在Web应用程序完全加载后立即处理并发送响应。

I guess the initialization could be deferred to a new thread and the request blocking could be accomplished with some middleware? Is there a library for this somewhere, so I don't have to start from scratch?

我猜想初始化可以推迟到一个新线程,并且可以通过一些中间件来实现请求的阻塞?是否有一个库可以做到这一点,这样我就不必从头开始了?

英文:

I would like to set up Flask so that it first sets up the listening socket, then runs some initialization code, then holds all incoming request processing until the initialization is complete. How do I set that up?

My Flask app takes about 30s of initialization (loading AI models, etc.). These are required for all real endpoints. However, during development, it is frustrating having to wait and watch for this to complete, before beginning with frontend interactions.

I remember old Tomcats (~15 years ago, haven't used it since) having this exact behavior: you could already send a request from an early stage of initialization, and then it would keep the connection open and process and send the response as soon as the webapp was fully loaded.

I guess the initialization could be deferred to a new thread and the request blocking could be accomplished with some middleware? Is there a library for this somewhere, so I don't have to start from scratch?

答案1

得分: 1

查看下面的代码是否有帮助。

@app.route('/')
def index():

    # 在一个单独的线程中开始初始化

    executor.submit(init_func)

    # 等待初始化完成

    while not executor.futures.done:
        threading.Event().wait(0.1)

    # 返回响应

    return 'Hello, World!'

我们使用Flask-Executor扩展来在单独的线程中执行初始化函数。我们还使用了threading模块来阻塞主线程,直到初始化完成。

英文:

See if the below code helps.

@app.route('/')
def index():

    # Start the initialization in a separate thread

    executor.submit(init_func)

    # Wait for the initialization to complete

    while not executor.futures.done:
        threading.Event().wait(0.1)

    # Return the response

    return 'Hello, World!'

we're using the Flask-Executor extension to execute the initialization function in a separate thread. We're also using the threading module to block the main thread until the initialization is complete.

答案2

得分: 0

Here's the translated content without the code:

Looking further into @manish-dixit's answer, Flash-Executor didn't quite work for me, but it seemed that the executor pattern is the simplest approach here. So here's my solution to the problem, using plain Python executors:

Here's a more complete example, including a decorator, that can also be run for demonstration purposes: flask_concurrent_blocking_initialization_example.py

英文:

Looking further into @manish-dixit's answer, Flash-Executor didn't quite work for me, but it seemed that the executor pattern is the simplest approach here. So here's my solution to the problem, using plain Python executors:

def long_running_initialization():
    # Long running initialization code goes here

app = Flask(__name__)

# create executor -- we only need a single worker, because we only want to run a single task on it ever
executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)

# the initialization will take a long time, so kick it off asap, whether there's incoming requests or not!
initialization_future = executor.submit(long_running_initialization)

@app.route('/')
def access_data():
    concurrent.futures.wait([initialization_future])
    # now we can access the fully initialized data set
    return f'Data: {data}'

Here's a more complete example, including a decorator, that can also be run for demonstration purposes:
flask_concurrent_blocking_initialization_example.py

huangapple
  • 本文由 发表于 2023年4月13日 19:55:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76005122.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定