Cannot perform I/O on behalf of a different request in Cloudflare Workers

Ok, so this may be a long one... I have several cloudflare workers that write or request data from Xata. When I do a single request using the TypeScript SDK, it works OK. When I do several requests like in a await Promise.all(array.map(async arrayElem => queryToXata(arrayElem))), then I get an error like:

Unable to retrieve metrics for report rec_REDACTED Error: Cannot perform I/O
on behalf of a different request. I/O objects (such as streams, request/response bodies, and
others) created in the context of one request handler cannot be accessed from a different
request's handler. This is a limitation of Cloudflare Workers which allows us to improve overall
performance.

Unable to retrieve metrics for report rec_REDACTED Error: Cannot perform I/O
on behalf of a different request. I/O objects (such as streams, request/response bodies, and
others) created in the context of one request handler cannot be accessed from a different
request's handler. This is a limitation of Cloudflare Workers which allows us to improve overall
performance.
This is coming from the Cloudflare Worker SDK, Wrangler. I have attached the stacktrace. I have tried creating the xata client on each method I call, so it is separated... but to no avail. If you request or need more information, i'll be happy to share code, or even do a screensharing session, etc. I want to discard if this is something from the Xata SDK, or it is something else,...
6 Replies
kostas
kostas8mo ago
It looks like this issue is generic in the Workers runtime and not specific to using the Xata SDK I.e. it comes up with plain fetch in this article https://blog.cloudflare.com/miniflare-and-workerd/ Seems the worker can't handle multiple concurrent fetch requests in a promise. I'll ask around our team if we have any recommendations, but what Xata SDK calls are your running in it? If it is queries could they perhaps be combined to a single call with OR clauses ($any operator https://xata.io/docs/sdk/filtering#control-operators) ? Or if they are creates, send in bulk.
Eusebio Trigo
Eusebio TrigoOP8mo ago
Yup, I have looked for this issue and it is common, but don't see a "straight answer". I've got queries like
const totals = await dbClient.sql<{ total_orders: number, total_sellers: number }>`
SELECT COUNT(DISTINCT (transactions.order)) AS total_orders,
COUNT(DISTINCT (transactions.shop)) AS total_sellers
FROM transactions
WHERE transactions.report = ${report_id}`;

const subquery = `SELECT DISTINCT (o.id)
FROM transactions t,
orders o
WHERE t.report = '${report_id}'
AND t.order = o.id`;

const total_amounts = await dbClient.sql<{
total_invoiced: number,
total_commission: number;
}>`SELECT SUM(orders.total_price) AS total_invoiced, SUM(orders.total_commission) AS total_commission
FROM orders
WHERE orders.id in (${subquery})`;
const totals = await dbClient.sql<{ total_orders: number, total_sellers: number }>`
SELECT COUNT(DISTINCT (transactions.order)) AS total_orders,
COUNT(DISTINCT (transactions.shop)) AS total_sellers
FROM transactions
WHERE transactions.report = ${report_id}`;

const subquery = `SELECT DISTINCT (o.id)
FROM transactions t,
orders o
WHERE t.report = '${report_id}'
AND t.order = o.id`;

const total_amounts = await dbClient.sql<{
total_invoiced: number,
total_commission: number;
}>`SELECT SUM(orders.total_price) AS total_invoiced, SUM(orders.total_commission) AS total_commission
FROM orders
WHERE orders.id in (${subquery})`;
And it happens to us both in a deployed worker and in local development.
kostas
kostas8mo ago
Thanks for the details - I've asked around, and will let you know if we have some suggestions. My understanding is that a Promise and a fetch request (Xata call) should be mapped one-to-one though.
Eusebio Trigo
Eusebio TrigoOP8mo ago
Yeah, that's my fear. Instead of a Promise.all( - send async requests using fetch -) that would send the requests in parallel, would need to send them using a good-old for loop with IO blocking, and getting each of the requests in sequence. Thanks for your help!
copper
copper4mo ago
@Eusebio Trigo are you still on Cloudflare + Xata?
Eusebio Trigo
Eusebio TrigoOP4mo ago
We were using it in all our workers. But due to reasons, we stopped all activities, and found other jobs.
Want results from more Discord servers?
Add your server