Cloud Run Readablestream需要5分钟来取消enqueue



我创建了一个适配器节点Sveltekit API端点,它使用可读流传输引号。当我退出客户端路由时,流媒体必须停止。使用Sveltekit "npm run "(vite dev)或者使用Windows桌面容器(node build)

onDestroy(async () => {
await reader.cancel();   // stop streaming
controller.abort();      // signal fetch abort
});

但是当我在Google Cloud Run上构建和部署节点容器时,流工作得很好。除非我退出客户端路由:API端点继续流式传输。日志显示:在API服务器上,enqueus又持续了5分钟,之后是一个延迟的Readablestream cancel()。

为什么客户端cancel/abort和服务器端的cancel之间有5分钟的间隔?

API +server.js
import { YahooFinanceTicker } from "yahoo-finance-ticker";
/** @type {import('./$types').RequestHandler} */
export async function POST({ request }) {
const { logging, symbols } = await request.json();
const controller = new AbortController();
const ticker = new YahooFinanceTicker();
ticker.setLogging(logging);
if (logging) console.log("api ticker", symbols);
const stream = new ReadableStream({
start(controller) {
(async () => {
const tickerListener = await ticker.subscribe(symbols);
tickerListener.on("ticker", (quote) => {
if (logging) console.log("api", JSON.stringify(quote, ["id", "price", "changePercent"]));
controller.enqueue(JSON.stringify(quote, ["id", "price", "changePercent"]));
});
})().catch(err => console.error(`api listen exeption: ${err}`));
},
cancel() {   // arrives after 5 minutes !!!
console.log("api", "cancel: unsubscribe ticker and abort");
ticker.unsubscribe();
controller.abort();
},
});
return new Response(stream, {
headers: {
'content-type': 'text/event-stream',
}
});
}

路线+ page.svelte

const controller = new AbortController();
let reader = null;
const signal = controller.signal;
async function streaming(params) {
try {
const response = await fetch("/api/yahoo-finance-ticker", {
method: "POST",
body: JSON.stringify(params),
headers: {
"content-type": "application/json",
},
signal: signal,
});
const stream = response.body.pipeThrough(new TextDecoderStream("utf-8"));
reader = stream.getReader();
while (true) {
const { value, done } = await reader.read();
if (logging) console.log("resp", done, value);
if (done) break;
... and more to get the quotes
}
} catch (err) {
if (!["AbortError"].includes(err.name)) throw err;
}
}
...

您正在观察的行为是预期的,Cloud Run不支持客户端断开连接。

在这篇文章中提到,

Cloud Run(完全管理)目前只支持服务器端流媒体。只有"服务器端流";基本上就是当"client"断开连接,"server"Will不知道,Will继续你的请求。这是因为"server"不是直接连接到"客户";以及"客户"的要求。被缓冲(全部),然后发送到"服务器"。

你也可以查看这个类似的线程

这是一个已知的问题,已经有一个公开的问题存在。你可以在以后的更新中关注这个问题,也可以在那里添加你的关注。

最新更新