遇到 Deno 意外的内部错误
2022-11-03
454
我通过 Deno TypeScript 中的 fetch-API 进行了大量提取。现在的问题是,我随机收到以下错误(无法被 try-catch 捕获):
error: Uncaught (in promise) TypeError: error sending request for url (https://www.googleapis.com/calendar/v3/calendars/****@group.calendar.google.com/events/?calendarId=****group.calendar.google.com): http2 error: stream error received: unexpected internal error encountered
const result: Response = await fetch(url, {
^
at async mainFetch (deno:ext/fetch/26_fetch.js:288:14)
at async fetch (deno:ext/fetch/26_fetch.js:505:9)
at async gFetchEvent (file:///home/****/my_script.ts:98:27)
我不知道如何修复它。这是一个 Deno 错误吗?
我安装了以下 deno 版本:
deno 1.25.2 (release, x86_64-unknown-linux-gnu)
v8 10.6.194.5
typescript 4.7.4
没有特定的代码行会破坏我的程序,只是过了一段时间(可能是几分钟,也可能是几天)我的程序就会因这个错误而崩溃。
它只出现在我的 Ubuntu 20.04.5 LTS vServer by 1blu 上,硬件规格如下:
H/W path Device Class Description
=============================================
system Computer
/0 bus Motherboard
/0/0 memory 8GiB System memory
/0/1 processor AMD EPYC 7452 32-Core Processor
/1 veth09bb0e5 network Ethernet interface
/2 veth0ab53b0 network Ethernet interface
/3 veth62387d0 network Ethernet interface
/4 veth7dbc5b2 network Ethernet interface
/5 vethb66edc6 network Ethernet interface
(
sudo lshw -short
的输出)
我主脚本中的代码:
try {
await main()
} catch (e) {
console.log(new Date(), e.stack)
Deno.writeTextFileSync(`logs/${Date.now()}`, "" + e.stack)
}
我的主要函数
// this program checks changes in my school schedule and automatically puts them in my google calendar
export default async function main() {
await Kantplaner.init()
while (true) {
// MKDate is just a class that extends Date for more functionallity, nothing special
const start_day = new MKDate(Date.now())
// repeats 14 times for the next 14 days
for (let i = 0; i < 14; i++) {
const date: MKDate = i ? start_day.nextDate(1) : start_day
// get my schedule from my school's site
const vplan: VPlan | null = await Indiware(date)
if (!vplan) continue
// fetch the existing events with google calendar api and check if something in the meantime changed
const calendar = await Kantplaner.list_events(date)
// male one big object containing all indices that were previously built by `await Indiware(date)`
const GrandIndex = { ...vplan.data.KlassenIndex, ...vplan.data.LehrerIndex }
for (const item of calendar.items) {
const stundenNr = "some_string"
const stundenMitDerID = GrandIndex[stundenNr]
// if the event is not in my school's schedule anymore, delete it
if (!stundenMitDerID) {
await Kantplaner.delete_event(item.id)
continue
}
// for every other event check differences and update the corresponding Google event
// `stundenMitDerID` is an array of events with the same id (can happen at my school)
for (let i = 0; i < stundenMitDerID.length; ++i) {
// ... create update (doesn't matter)
const update: Kantplaner.Update = {}
await Kantplaner.update_event(item.id, update)
// remove lesson from index to avoid another creation
GrandIndex[stundenNr].splice(i)
if (GrandIndex[stundenNr].length == 0) delete GrandIndex[stundenNr]
}
}
// create every remainig event
for (const stundenNr in GrandIndex) {
const stundenMitDerID = GrandIndex[stundenNr]
for (let i = 0; i < stundenMitDerID.length; ++i) {
await Kantplaner.create_event({
// event data
})
}
}
}
// wait one minute to reduce unnecessary fetches
await new Promise(r => setTimeout(r, 60_000))
}
}
所有出现的
gFetchEvent
:
export async function list_events(date: MKDate, TIME_SHIFT: string): Promise<Calendar> {
const calendar: Calendar | null = await gFetchEvent("/", "GET", {
timeMin: date.format(`yyyy-MM-ddT00:00:00${TIME_SHIFT}`),
timeMax: date.format(`yyyy-MM-ddT23:59:59${TIME_SHIFT}`),
})
if (!calendar) return EMPTY_CALENDAR
let nextPageToken = calendar.nextPageToken
while (nextPageToken) {
const nextPage: Calendar = await gFetchEvent("/", "GET", {
pageToken: nextPageToken,
timeMin: date.format(`yyyy-MM-ddT00:00:00${TIME_SHIFT}`),
timeMax: date.format(`yyyy-MM-ddT23:59:59${TIME_SHIFT}`),
})
calendar.items.push(...nextPage.items)
nextPageToken = nextPage.nextPageToken
}
return calendar
}
export async function create_event(event: Event) {
await gFetchEvent("/", "POST", { calendarId: CALENDAR_ID }, event)
}
export async function update_event(eventId: string, update: Update) {
await gFetchEvent(`/${eventId}`, "PATCH", {
sendUpdates: "none"
}, update)
}
export async function delete_event(eventId: string) {
await gFetchEvent(`/${eventId}`, "DELETE", {
calendarId: CALENDAR_ID,
eventId: eventId,
sendUpdates: "none"
})
}
我fetch:
async function gFetchEvent(urlPath: string, method: string, params?: { [key: string]: string }, body?: any) {
if (!initiated) return null
const url = new URL(CALENDAR_API_URL + urlPath)
if (params) for (const key of Object.keys(params)) url.searchParams.append(key, params[key])
const result: Response = await fetch(url, {
headers: {
Authorization: "Bearer " + access_token,
Accept: "application/json",
"Content-Type": "application/json"
},
method: method,
body: JSON.stringify(body)
})
await new Promise(f => setTimeout(f, 100))
if (result.ok) {
const text = await result.text()
if (text.length > 1) return JSON.parse(text)
else return {}
} else if (result.status == 403) {
gFetchEvent(urlPath, method, params, body)
return
}
return null
}
每个函数调用(例如
list_events
或
update_event
)都会隐式调用
gFetchEvent
函数(使用不同的 url 和 )。
2个回答
您缺少
await
,没有它,错误将无法正确冒泡到
main
函数中的
try/catch
。
if (result.ok) {
const text = await result.text()
if (text.length > 1) return JSON.parse(text)
else return {}
} else if (result.status == 403) {
// You were missing an await here
const res = await gFetchEvent(urlPath, method, params, body)
return res;
// or just
// return gFetchEvent(urlPath, method, params, body);
}
或者,如果您不想在该路径中使用
await
,您可以将
.catch
处理程序附加到
gFetchEvent
以防止
Uncaught Promise
错误。
Marcos Casagrande
2022-11-05
感谢 @Marcos Casagrande,我意识到我调用了一个异步函数,该函数在没有等待的情况下抛出错误。如果提取没有抛出错误,那就不是问题。
但是提取的一些错误(很可能是网络错误)导致了这个错误的抛出。
MrKleeblatt
2022-11-05