Skip to content

Commit 08c9934

Browse files
author
Guy Bedford
authored
fix: event loop stall error no longer a panic (#934)
1 parent c4182d3 commit 08c9934

File tree

8 files changed

+373
-268
lines changed

8 files changed

+373
-268
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ env:
1212
fastly-cli_version: 10.8.10
1313

1414
jobs:
15-
1615
check-changelog:
17-
concurrency:
18-
group: ${{ github.head_ref }}-${{ github.workflow}}-check-changelog
19-
cancel-in-progress: true
2016
if: github.ref != 'refs/heads/main'
2117
runs-on: ubuntu-latest
2218
steps:
@@ -29,9 +25,6 @@ jobs:
2925
- run: npm run format-changelog
3026

3127
check-docusaurus:
32-
concurrency:
33-
group: ${{ github.head_ref }}-${{ github.workflow}}-check-docusaurus
34-
cancel-in-progress: true
3528
if: github.ref != 'refs/heads/main'
3629
runs-on: ubuntu-latest
3730
steps:
@@ -67,9 +60,6 @@ jobs:
6760
if: steps.cache-crate.outputs.cache-hit != 'true'
6861

6962
shellcheck:
70-
concurrency:
71-
group: ${{ github.head_ref }}-${{ github.workflow}}-shellcheck
72-
cancel-in-progress: true
7363
env:
7464
SHELLCHECK_VERSION: v0.8.0
7565
runs-on: ubuntu-latest
@@ -101,9 +91,6 @@ jobs:
10191
run: ci/shellcheck.sh
10292

10393
format:
104-
concurrency:
105-
group: ${{ github.head_ref }}-${{ github.workflow}}-format
106-
cancel-in-progress: true
10794
if: github.ref != 'refs/heads/main'
10895
runs-on: ubuntu-latest
10996
steps:
@@ -123,9 +110,6 @@ jobs:
123110
ci/rustfmt.sh
124111
125112
test-npm-package:
126-
concurrency:
127-
group: ${{ github.head_ref }}-${{ github.workflow}}-test-npm-package-${{matrix.node-version}}
128-
cancel-in-progress: true
129113
if: github.ref != 'refs/heads/main'
130114
runs-on: ubuntu-latest
131115
needs: [build]
@@ -254,11 +238,11 @@ jobs:
254238

255239
sdktest:
256240
concurrency:
257-
group: ${{ github.head_ref }}-${{ github.workflow}}-sdktest-${{matrix.profile}}-${{matrix.platform}}
258-
cancel-in-progress: true
241+
group: ${{ github.head_ref }}--sdktest-${{matrix.platform == 'compute' && matrix.profile || ''}}-${{matrix.platform}}
259242
if: github.ref != 'refs/heads/main'
260243
runs-on: ubuntu-latest
261244
strategy:
245+
fail-fast: false
262246
matrix:
263247
platform: [viceroy, compute]
264248
profile: [debug, release, weval]

integration-tests/js-compute/compare-downstream-response.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import compareHeaders from './compare-headers.js';
1212
}} configResponse
1313
* @param {import('undici').Dispatcher.ResponseData} actualResponse
1414
*/
15-
export async function compareDownstreamResponse (configResponse, actualResponse) {
15+
export async function compareDownstreamResponse (configResponse, actualResponse, actualBodyChunks) {
1616
let errors = [];
1717
// Status
1818
if (configResponse.status != actualResponse.statusCode) {
@@ -33,13 +33,8 @@ export async function compareDownstreamResponse (configResponse, actualResponse)
3333
// Check if we need to stream the response and check the chunks, or the whole body
3434
if (configResponse.body instanceof Array) {
3535
// Stream down the response
36-
let downstreamBody = actualResponse.body;
3736
let chunkNumber = 0;
38-
const downstreamTimeout = setTimeout(() => {
39-
console.error(`[DownstreamResponse: Body Chunk Timeout]`);
40-
process.exit(1);
41-
}, 30 * 1000);
42-
for await (const chunk of downstreamBody) {
37+
for (const chunk of actualBodyChunks) {
4338
const chunkString = chunk.toString('utf8');
4439

4540
// Check if the chunk is equal to what we expected
@@ -53,14 +48,12 @@ export async function compareDownstreamResponse (configResponse, actualResponse)
5348
}
5449
}
5550

56-
clearTimeout(downstreamTimeout);
57-
5851
if (chunkNumber !== configResponse.body.length) {
5952
errors.push(new Error(`[DownstreamResponse: Body Chunk mismatch] Expected: ${configResponse.body} - Got: (Incomplete stream, Number of chunks returned: ${chunkNumber})`));
6053
}
6154
} else {
6255
// Get the text, and check if it matches the test
63-
let downstreamBodyText = await actualResponse.body.text();
56+
const downstreamBodyText = Buffer.concat(actualBodyChunks.map(chunk => Buffer.from(chunk))).toString('utf8');
6457

6558
if (downstreamBodyText !== configResponse.body) {
6659
errors.push(new Error(`[DownstreamResponse: Body mismatch] Expected: ${configResponse.body} - Got: ${downstreamBodyText}`));

integration-tests/js-compute/fixtures/app/src/dynamic-backend.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { allowDynamicBackends } from "fastly:experimental";
55
import { pass, assert, assertDoesNotThrow, assertThrows, assertRejects, assertResolves } from "./assertions.js";
66
import { isRunningLocally, routes } from "./routes.js";
77

8-
/// The backend name is already in use.
9-
108
routes.set("/backend/timeout", async () => {
119
if (isRunningLocally()) {
1210
return pass('ok')

integration-tests/js-compute/fixtures/app/src/response.js

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,83 @@
33
import { routes } from "./routes.js";
44
import { pass, assert, assertThrows } from "./assertions.js";
55

6+
routes.set("/response/stall", async (event) => {
7+
return new Response(
8+
new ReadableStream({
9+
start(controller) {
10+
// stall
11+
},
12+
})
13+
);
14+
});
15+
616
routes.set("/response/text/guest-backed-stream", async () => {
7-
let contents = new Array(10).fill(new Uint8Array(500).fill(65))
8-
contents.push(new Uint8Array([0, 66]))
9-
contents.push(new Uint8Array([1,1,2,65]))
10-
let res = new Response(iteratableToStream(contents))
11-
let text = await res.text()
17+
let contents = new Array(10).fill(new Uint8Array(500).fill(65));
18+
contents.push(new Uint8Array([0, 66]));
19+
contents.push(new Uint8Array([1, 1, 2, 65]));
20+
let res = new Response(iteratableToStream(contents));
21+
let text = await res.text();
1222

13-
let error = assert(text, "A".repeat(5000) + '\x00B\x01\x01\x02A', `await res.text() === "a".repeat(5000)`)
14-
if (error) { return error }
15-
return pass()
16-
})
23+
let error = assert(
24+
text,
25+
"A".repeat(5000) + "\x00B\x01\x01\x02A",
26+
`await res.text() === "a".repeat(5000)`
27+
);
28+
if (error) {
29+
return error;
30+
}
31+
return pass();
32+
});
1733
routes.set("/response/json/guest-backed-stream", async () => {
18-
let obj = {a:1,b:2,c:{d:3}}
19-
let encoder = new TextEncoder()
20-
let contents = encoder.encode(JSON.stringify(obj))
21-
let res = new Response(iteratableToStream([contents]))
22-
let json = await res.json()
34+
let obj = { a: 1, b: 2, c: { d: 3 } };
35+
let encoder = new TextEncoder();
36+
let contents = encoder.encode(JSON.stringify(obj));
37+
let res = new Response(iteratableToStream([contents]));
38+
let json = await res.json();
2339

24-
let error = assert(json, obj, `await res.json() === obj`)
25-
if (error) { return error }
26-
return pass()
27-
})
40+
let error = assert(json, obj, `await res.json() === obj`);
41+
if (error) {
42+
return error;
43+
}
44+
return pass();
45+
});
2846
routes.set("/response/arrayBuffer/guest-backed-stream", async () => {
29-
let obj = {a:1,b:2,c:{d:3}}
30-
let encoder = new TextEncoder()
31-
let contents = encoder.encode(JSON.stringify(obj))
32-
let res = new Response(iteratableToStream([contents]))
33-
let json = await res.arrayBuffer()
47+
let obj = { a: 1, b: 2, c: { d: 3 } };
48+
let encoder = new TextEncoder();
49+
let contents = encoder.encode(JSON.stringify(obj));
50+
let res = new Response(iteratableToStream([contents]));
51+
let json = await res.arrayBuffer();
3452

35-
let error = assert(json, contents.buffer, `await res.json() === contents.buffer`)
36-
if (error) { return error }
37-
return pass()
38-
})
53+
let error = assert(
54+
json,
55+
contents.buffer,
56+
`await res.json() === contents.buffer`
57+
);
58+
if (error) {
59+
return error;
60+
}
61+
return pass();
62+
});
3963
routes.set("/response/ip-port-undefined", async () => {
40-
let res = new Response()
41-
let error = assert(res.ip, undefined)
42-
if (error) { return error }
43-
error = assert(res.port, undefined)
44-
if (error) { return error }
45-
return pass()
46-
})
64+
let res = new Response();
65+
let error = assert(res.ip, undefined);
66+
if (error) {
67+
return error;
68+
}
69+
error = assert(res.port, undefined);
70+
if (error) {
71+
return error;
72+
}
73+
return pass();
74+
});
4775

4876
function iteratableToStream(iterable) {
49-
return new ReadableStream({
50-
async pull(controller) {
51-
for await (const value of iterable) {
52-
controller.enqueue(value)
53-
}
54-
controller.close()
55-
}
56-
})
77+
return new ReadableStream({
78+
async pull(controller) {
79+
for await (const value of iterable) {
80+
controller.enqueue(value);
81+
}
82+
controller.close();
83+
},
84+
});
5785
}

integration-tests/js-compute/fixtures/app/tests.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4539,6 +4539,17 @@
45394539
"status": 200
45404540
}
45414541
},
4542+
"GET /response/stall": {
4543+
"body_streaming": "none",
4544+
"environments": ["viceroy", "compute"],
4545+
"downstream_request": {
4546+
"method": "GET",
4547+
"pathname": "/response/stall"
4548+
},
4549+
"downstream_response": {
4550+
"status": 200
4551+
}
4552+
},
45424553
"GET /response/text/guest-backed-stream": {
45434554
"environments": ["viceroy", "compute"],
45444555
"downstream_request": {

0 commit comments

Comments
 (0)