如何在 Flask 中线程化外部挂起的 API 调用?

How Do You Thread an External Hanging API Call in Flask?

不谈细节,我正在通过 IPFS 和 Flask 编写一个开源 P2P 社交网络——我知道,它已经完成了。我选择 Flask 因为 pyinstaller 可以把它放在一个 exe 文件中。

我正在尝试每 10 分钟更新一次我的 IPNS,以发布我在上述 10 分钟内添加到网络的所有状态更新。设置 class(来自 library.py)中的 cron 函数是存储更新程序函数的地方。起初,我从设置的 init 线程化了 cron 函数。服务器挂了。然后我将线程处理移至 app.before_first_request。服务器仍然挂起。

https://pastebin.com/bXHTuH83 (main.py)

from flask import Flask, jsonify
from library import *

#=========================TO BE DELETED=========================================
def pretty(json):
    json = dumps(loads(json), indent=4, sort_keys=True)
    return json
#===============================================================================

app = Flask(__name__)

GANN = setup()

@app.before_first_request
def cron_job():
    Thread(target=GANN.cron())

@app.route("/")
def home():
    return "Hello World!!!"

if __name__ == "__main__":
    app.run(port="80", debug=True, threaded=True)

https://pastebin.com/W5P8Tpvd (library.py)

from threading import Thread
from time import time, sleep
import urllib.request
from json import loads, dumps

def api(*argv, **kwargs):
    url = "http://127.0.0.1:5001/api/v0/"
    for arg in argv:
        arg = arg.replace(" ", "/")
        if arg[:-1] != "/":
            arg += "/"
        url += arg
    url = url[0:-1]
    if kwargs:
        url+="?"
        for val in kwargs:
            url = url + val + "=" + kwargs[val] + "&"
        url = url[0:-1]
        print(url)
    try:
        with urllib.request.urlopen(url, timeout=300) as response:
            return response.read()
    except:
        return b"""{"ERROR": "CANNOT CONNECT TO IPFS!"}"""

class setup():

    def __init__(self):
        api("files", "mkdir", arg="/GANN", parents="True")
        self.root_hash = ""

    def update_root(self):
        try:
            for entry in loads(api("files", "ls", l="True").decode())["Entries"]:
                if entry["Name"] == "GANN":
                    self.root_hash = entry["Hash"]
        except:
            return """{"ERROR": "CANNOT FIND ROOT DIRECTORY"}"""

    def publish_root(self):
        api("name", "publish", arg=self.root_hash)

    def cron(self):
        while True:
            print("CRON Thread Started!")
            self.update_root()
            self.publish_root()
            sleep(600)

我在网上搜索了几天,但还没有找到一种线程技术,它可以从主进程中分离出来,并且不会让服务器停止接受其他请求。我相信我处于单流连接上,因为 IPFS 在启动时会阻止与我家中所有其他设备的连接。 CLI IPNS 更新需要几分钟才能完成,所以我将 urllib 的超时设置为 300 秒。

好吧,我认为线程代码不正确。

@app.before_first_request
def cron_job():
    Thread(target=GANN.cron())

您在这里创建了一个 Thread 对象。参数必须是 callable,但您已经在此处调用了您的方法。所以正确的方法是

Thread(target=GANN.cron)

所以线程可以稍后调用cron函数。话虽如此,Thread 必须启动,所以它会调用您提供的函数目标。所以一定是ike

thread_cron = Thread(target=GANN.cron)
thread_cron.start()

由于您调用了 GANN.cron() ,该方法开始执行并且您的应用挂起!