|
198 | 198 | }; |
199 | 199 | }); |
200 | 200 |
|
201 | | - // If the worker takes 12 seconds, kill it and return an error code. |
202 | | - // Most clients take longer than 10 seconds to complete the upload and |
203 | | - // finish sending the buffer's content, sometimes hitting the socket's |
204 | | - // timeout of 15 seconds. This makes sure uploads terminate on time and |
205 | | - // get a chance to send one last measurement after 10s. |
206 | | - const workerTimeout = setTimeout(() => worker.resolve(0), 12000); |
| 201 | + // Connection timeout: if the WebSocket never opens (and never |
| 202 | + // fires onerror/onclose), resolve after 10s to prevent the |
| 203 | + // promise from hanging indefinitely. |
| 204 | + const connTimeout = setTimeout(() => worker.resolve(0), 10000); |
| 205 | + |
| 206 | + // The test duration timeout is set when the worker reports |
| 207 | + // 'start' (i.e. sock.onopen), so that WS+TLS handshake time |
| 208 | + // does not eat into the test duration. |
| 209 | + let workerTimeout; |
207 | 210 |
|
208 | 211 | // This is how the worker communicates back to the main thread of |
209 | 212 | // execution. The MsgTpe of `ev` determines which callback the message |
210 | 213 | // gets forwarded to. |
211 | 214 | worker.onmessage = function(ev) { |
212 | 215 | if (!ev.data || !ev.data.MsgType || ev.data.MsgType === 'error') { |
| 216 | + clearTimeout(connTimeout); |
213 | 217 | clearTimeout(workerTimeout); |
214 | 218 | worker.resolve(1); |
215 | 219 | const msg = (!ev.data) ? `${testType} error` : ev.data.Error; |
216 | 220 | callbacks.error(msg); |
217 | 221 | } else if (ev.data.MsgType === 'start') { |
| 222 | + clearTimeout(connTimeout); |
| 223 | + // Safety timeout anchored to connect, not worker creation. |
| 224 | + // 12s gives the server's 10s duration time to finish plus |
| 225 | + // margin for the upload buffer to drain. |
| 226 | + workerTimeout = setTimeout(() => worker.resolve(0), 12000); |
218 | 227 | callbacks.start(ev.data.Data); |
219 | 228 | } else if (ev.data.MsgType == 'measurement') { |
220 | 229 | // For performance reasons, we parse the JSON outside of the thread |
|
241 | 250 | // We can't start the worker until we know the right server, so we wait |
242 | 251 | // here to find that out. |
243 | 252 | const urls = await urlPromise.catch((err) => { |
244 | | - // Clear timer, terminate the worker and rethrow the error. |
| 253 | + // Clear timers, terminate the worker and rethrow the error. |
| 254 | + clearTimeout(connTimeout); |
245 | 255 | clearTimeout(workerTimeout); |
246 | 256 | worker.resolve(2); |
247 | 257 | throw err; |
|
0 commit comments