mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
feat(mcp): add 30s request timeouts to prevent Durable Object stalls
- Add AbortSignal.timeout(30_000) to fetch calls in getProjects() and getDocuments() in apps/mcp/src/client.ts - Pass timeout: 30_000 to the Supermemory SDK constructor so SDK calls (search, add, forget, profile) are bounded - Add AbortSignal.timeout(30_000) to fetch in validateApiKey() and validateOAuthToken() in apps/mcp/src/auth.ts - Add AbortSignal.timeout(30_000) to the /.well-known/oauth-authorization-server proxy fetch in apps/mcp/src/index.ts - Add AbortError/TimeoutError guard in handleError() that maps timeout errors to a clear user-facing message Fixes unbounded upstream fetches that blocked the SupermemoryMCP Durable Object event loop causing durable_object_subrequest wall-time spikes. Co-authored-by: Dhravya Shah <dhravya@supermemory.com>
This commit is contained in:
parent
cf47d73126
commit
f908164403
3 changed files with 19 additions and 0 deletions
|
|
@ -32,6 +32,7 @@ export async function validateApiKey(
|
|||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
|
||||
if (!sessionResponse.ok) {
|
||||
|
|
@ -103,6 +104,7 @@ export async function validateOAuthToken(
|
|||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
|
||||
if (!sessionResponse.ok) {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ export class SupermemoryClient {
|
|||
this.client = new Supermemory({
|
||||
apiKey: bearerToken,
|
||||
baseURL: apiUrl,
|
||||
timeout: 30_000,
|
||||
})
|
||||
this.containerTag = containerTag || DEFAULT_PROJECT_ID
|
||||
}
|
||||
|
|
@ -336,6 +337,7 @@ export class SupermemoryClient {
|
|||
Authorization: `Bearer ${this.bearerToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
|
|
@ -374,6 +376,7 @@ export class SupermemoryClient {
|
|||
order: "desc",
|
||||
containerTags,
|
||||
}),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw Object.assign(new Error("Failed to fetch documents"), {
|
||||
|
|
@ -387,6 +390,19 @@ export class SupermemoryClient {
|
|||
}
|
||||
|
||||
private handleError(error: unknown): never {
|
||||
// Handle request timeout errors (AbortError from AbortSignal.timeout or SDK TimeoutError)
|
||||
if (error instanceof Error) {
|
||||
if (
|
||||
error.name === "AbortError" ||
|
||||
error.name === "TimeoutError" ||
|
||||
error.message.toLowerCase().includes("timeout")
|
||||
) {
|
||||
throw new Error(
|
||||
"Request to Supermemory API timed out. Please try again.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle network/fetch errors
|
||||
if (error instanceof TypeError) {
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ app.get("/.well-known/oauth-authorization-server", async (c) => {
|
|||
// Fetch the authorization server metadata from the main API
|
||||
const response = await fetch(
|
||||
`${apiUrl}/.well-known/oauth-authorization-server`,
|
||||
{ signal: AbortSignal.timeout(30_000) },
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue