我有一个后端(Quart)API作为事件源,处理一个耗时的操作.这个耗时的任务需要大约2分钟的时间来生成一些响应.

为了保持连接,我每10秒发送一次心跳.我可以看到所有这些东西都在工作,我的reaction前端正确地接收到事件.

但是,问题是每隔1分钟,api请求就会被取消,并创建另一个请求到同一端点.

我想要的是,继续发送心跳到客户端,直到耗时的任务完成(2分钟后).

下面是我的后端逻辑,看起来像Python(Python):

import asyncio
from quart import Quart, Response, websocket

app = Quart(__name__)

@app.after_request
async def add_cors_headers(response):
    response.headers['Access-Control-Allow-Origin'] = 'http://localhost:3000'
    response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
    return response

async def time_consuming_task(queue):
    # Simulate a time-consuming task
    await asyncio.sleep(120)
    # Once the task is completed, put the result in the queue
    await queue.put("Task completed")

async def in_progress_events(queue):
    i = 0
    while True:
        yield f"data: {i}\n\n"
        i += 1
        await asyncio.sleep(1)

@app.route('/sse')
async def sse():
    # Create a queue to communicate with the time-consuming task
    queue = asyncio.Queue()

    # Start the time-consuming task
    asyncio.create_task(time_consuming_task(queue))

    async def event_stream():
        while True:
            async for event in in_progress_events(queue):
                yield event

                # Check if there's a result in the queue
                if not queue.empty():
                    result = await queue.get()
                    yield f"data: {result}\n\n"
                    yield "event: close\ndata: Connection closed\n\n"
                    return

            # Send a heartbeat event to keep the connection alive
            yield "event: heartbeat\ndata: \n\n"
            await asyncio.sleep(50)  # Send a heartbeat every 50 seconds

    response = Response(event_stream(), content_type='text/event-stream')
    response.headers['Connection'] = 'keep-alive'
    response.headers['Cache-Control'] = 'no-cache'
    response.headers['Transfer-Encoding'] = 'chunked'
    return response

if __name__ == '__main__':
    app.run()

此外,前端逻辑:

import React, { useEffect, useState } from 'react';

function SSEComponent() {
  const [data, setData] = useState('');

  useEffect(() => {
    const eventSource = new EventSource('http://localhost:5000/sse');

    eventSource.onmessage = (event) => {
        console.log("onmessage", event.data);
      setData(event.data);
    };

    eventSource.addEventListener('close', () => {
        console.log("onclose");
      eventSource.close();
    });

    eventSource.addEventListener('heartbeat', () => {
        // Handle heartbeat events
        console.log('Received heartbeat event');
      });

    eventSource.onerror = (error) => {
        console.log("error", error);
    };

    return () => {
      eventSource.close();
    };
  }, []);

  return (
    <div>
      <h2>Server-Sent Events Data:</h2>
      <p>{data}</p>
    </div>
  );
}

export default SSEComponent;

console log with multiple same api calls

推荐答案

默认情况下,Quart将超时超过60秒的响应,对于服务器发送事件路由,超时应设置为None,即response.timeout = None.See docs

Python相关问答推荐

Odoo 14 hr. emergency.public内的二进制字段

如何比较numPy数组中的两个图像以获取它们不同的像素

如何将双框框列中的成对变成两个新列

2D空间中的反旋算法

按顺序合并2个词典列表

从dict的列中分钟

Pandas—合并数据帧,在公共列上保留非空值,在另一列上保留平均值

avxspan与pandas period_range

在含噪声的3D点网格中识别4连通点模式

Python逻辑操作作为Pandas中的条件

用砂箱开发Web统计分析

如何使regex代码只适用于空的目标单元格

Maya Python脚本将纹理应用于所有对象,而不是选定对象

在用于Python的Bokeh包中设置按钮的样式

使用嵌套对象字段的Qdrant过滤

Python类型提示:对于一个可以迭代的变量,我应该使用什么?

Pandas:计数器的滚动和,复位

PYTHON中的pd.wide_to_long比较慢

如何在Python中实现高效地支持字典和堆操作的缓存?

解析CSV文件以将详细信息添加到XML文件