Skip to content

Commit e7179b5

Browse files
authored
feat: Adding timeout to publisher config for api requests and uploads (#7028)
* Adding timeout to publish config. Adding test for validating too short of a timeout. Expect upload to throw/reject Request timed out. Adding null type in docs and updating documentation to state 2min default
1 parent 9498261 commit e7179b5

File tree

15 files changed

+159
-16
lines changed

15 files changed

+159
-16
lines changed

.changeset/chatty-trains-agree.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"app-builder-lib": minor
3+
"builder-util-runtime": minor
4+
"builder-util": minor
5+
"electron-publish": minor
6+
---
7+
8+
feat: Adding timeout to publisher config for api requests and uploads

docs/api/electron-builder.md

+1
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,7 @@ return path.join(target.outDir, <code>__${target.name}-${getArtifactArchName(arc
13041304
<li><code id="UploadTask-fileContent">fileContent</code> module:global.Buffer | “undefined”</li>
13051305
<li><strong><code id="UploadTask-arch">arch</code></strong> <a href="#Arch">Arch</a> | “undefined”</li>
13061306
<li><code id="UploadTask-safeArtifactName">safeArtifactName</code> String | “undefined”</li>
1307+
<li><code id="UploadTask-timeout">timeout</code> Number | “undefined”</li>
13071308
</ul>
13081309
<p><a name="HttpPublisher"></a></p>
13091310
<h2 id="httppublisher-%E2%87%90-publisher">HttpPublisher ⇐ <code><a href="#Publisher">Publisher</a></code></h2>

docs/configuration/publish.md

+15
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ In all publish options <a href="/file-patterns#file-macros">File Macros</a> are
132132
<li>
133133
<p><code id="GenericServerOptions-requestHeaders">requestHeaders</code> module:http.OutgoingHttpHeaders - Any custom request headers</p>
134134
</li>
135+
<li>
136+
<p><code id="GenericServerOptions-timeout">timeout</code> = <code>60000</code> Number | “undefined” - Request timeout in milliseconds. (Default is 2 minutes; O is ignored)</p>
137+
</li>
135138
</ul>
136139
<h2 id="githuboptions">GithubOptions</h2>
137140
<p><a href="https://help.github.com/articles/about-releases/">GitHub</a> options.</p>
@@ -179,6 +182,9 @@ Define <code>GH_TOKEN</code> environment variable.</p>
179182
<li>
180183
<p><code id="GithubOptions-requestHeaders">requestHeaders</code> module:http.OutgoingHttpHeaders - Any custom request headers</p>
181184
</li>
185+
<li>
186+
<p><code id="GithubOptions-timeout">timeout</code> = <code>60000</code> Number | “undefined” - Request timeout in milliseconds. (Default is 2 minutes; O is ignored)</p>
187+
</li>
182188
</ul>
183189
<h2 id="snapstoreoptions">SnapStoreOptions</h2>
184190
<p><a href="https://snapcraft.io/">Snap Store</a> options.</p>
@@ -196,6 +202,9 @@ Define <code>GH_TOKEN</code> environment variable.</p>
196202
<li>
197203
<p><code id="SnapStoreOptions-requestHeaders">requestHeaders</code> module:http.OutgoingHttpHeaders - Any custom request headers</p>
198204
</li>
205+
<li>
206+
<p><code id="SnapStoreOptions-timeout">timeout</code> = <code>60000</code> Number | “undefined” - Request timeout in milliseconds. (Default is 2 minutes; O is ignored)</p>
207+
</li>
199208
</ul>
200209
<h2 id="spacesoptions">SpacesOptions</h2>
201210
<p><a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-digitalocean-spaces">DigitalOcean Spaces</a> options.
@@ -228,6 +237,9 @@ Define <code>KEYGEN_TOKEN</code> environment variable.</p>
228237
<li>
229238
<p><code id="KeygenOptions-requestHeaders">requestHeaders</code> module:http.OutgoingHttpHeaders - Any custom request headers</p>
230239
</li>
240+
<li>
241+
<p><code id="KeygenOptions-timeout">timeout</code> = <code>60000</code> Number | “undefined” - Request timeout in milliseconds. (Default is 2 minutes; O is ignored)</p>
242+
</li>
231243
</ul>
232244
<h2 id="bitbucketoptions">BitbucketOptions</h2>
233245
<p>Bitbucket options.
@@ -256,6 +268,9 @@ Define <code>BITBUCKET_TOKEN</code> environment variable.</p>
256268
<li>
257269
<p><code id="BitbucketOptions-requestHeaders">requestHeaders</code> module:http.OutgoingHttpHeaders - Any custom request headers</p>
258270
</li>
271+
<li>
272+
<p><code id="BitbucketOptions-timeout">timeout</code> = <code>60000</code> Number | “undefined” - Request timeout in milliseconds. (Default is 2 minutes; O is ignored)</p>
273+
</li>
259274
</ul>
260275
<h2 id="s3options">S3Options</h2>
261276
<p><a href="https://aws.amazon.com/s3/">Amazon S3</a> options.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"generate-changeset": "pnpm changeset",
3030
"generate-docs": "pnpm compile && pnpm jsdoc && pnpm jsdoc2md2html",
3131
"generate-schema": "typescript-json-schema packages/app-builder-lib/tsconfig-scheme.json Configuration --out packages/app-builder-lib/scheme.json --noExtraProps --useTypeOfKeyword --strictNullChecks --required && node ./scripts/fix-schema.js",
32+
"generate-all": "pnpm generate-schema && pnpm generate-docs && pnpm prettier",
3233
"ci:test": "node ./test/out/helpers/runTests.js",
3334
"ci:version": "pnpm changelog && changeset version && node scripts/update-package-version-export.js && pnpm run generate-schema && pnpm run generate-docs && pnpm run prettier && git add .",
3435
"ci:publish": "pnpm compile && pnpm publish -r && changeset tag",

packages/app-builder-lib/scheme.json

+64
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,14 @@
381381
"description": "Repository slug/name",
382382
"type": "string"
383383
},
384+
"timeout": {
385+
"default": 60000,
386+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
387+
"type": [
388+
"null",
389+
"number"
390+
]
391+
},
384392
"token": {
385393
"description": "The access token to support auto-update from private bitbucket repositories.",
386394
"type": [
@@ -478,6 +486,14 @@
478486
"$ref": "#/definitions/OutgoingHttpHeaders",
479487
"description": "Any custom request headers"
480488
},
489+
"timeout": {
490+
"default": 60000,
491+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
492+
"type": [
493+
"null",
494+
"number"
495+
]
496+
},
481497
"updateProvider": {
482498
"description": "The Provider to provide UpdateInfo regarding available updates. Required\nto use custom providers with electron-updater.",
483499
"typeof": "function"
@@ -1358,6 +1374,14 @@
13581374
"$ref": "#/definitions/OutgoingHttpHeaders",
13591375
"description": "Any custom request headers"
13601376
},
1377+
"timeout": {
1378+
"default": 60000,
1379+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
1380+
"type": [
1381+
"null",
1382+
"number"
1383+
]
1384+
},
13611385
"updaterCacheDirName": {
13621386
"type": [
13631387
"null",
@@ -1482,6 +1506,14 @@
14821506
"$ref": "#/definitions/OutgoingHttpHeaders",
14831507
"description": "Any custom request headers"
14841508
},
1509+
"timeout": {
1510+
"default": 60000,
1511+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
1512+
"type": [
1513+
"null",
1514+
"number"
1515+
]
1516+
},
14851517
"token": {
14861518
"description": "The access token to support auto-update from private github repositories. Never specify it in the configuration files. Only for [setFeedURL](/auto-update#appupdatersetfeedurloptions).",
14871519
"type": [
@@ -1573,6 +1605,14 @@
15731605
"$ref": "#/definitions/OutgoingHttpHeaders",
15741606
"description": "Any custom request headers"
15751607
},
1608+
"timeout": {
1609+
"default": 60000,
1610+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
1611+
"type": [
1612+
"null",
1613+
"number"
1614+
]
1615+
},
15761616
"updaterCacheDirName": {
15771617
"type": [
15781618
"null",
@@ -4876,6 +4916,14 @@
48764916
"default": "STANDARD",
48774917
"description": "The type of storage to use for the object."
48784918
},
4919+
"timeout": {
4920+
"default": 60000,
4921+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
4922+
"type": [
4923+
"null",
4924+
"number"
4925+
]
4926+
},
48794927
"updaterCacheDirName": {
48804928
"type": [
48814929
"null",
@@ -5324,6 +5372,14 @@
53245372
"$ref": "#/definitions/OutgoingHttpHeaders",
53255373
"description": "Any custom request headers"
53265374
},
5375+
"timeout": {
5376+
"default": 60000,
5377+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
5378+
"type": [
5379+
"null",
5380+
"number"
5381+
]
5382+
},
53275383
"updaterCacheDirName": {
53285384
"type": [
53295385
"null",
@@ -5409,6 +5465,14 @@
54095465
"$ref": "#/definitions/OutgoingHttpHeaders",
54105466
"description": "Any custom request headers"
54115467
},
5468+
"timeout": {
5469+
"default": 60000,
5470+
"description": "Request timeout in milliseconds. (Default is 2 minutes; O is ignored)",
5471+
"type": [
5472+
"null",
5473+
"number"
5474+
]
5475+
},
54125476
"updaterCacheDirName": {
54135477
"type": [
54145478
"null",

packages/app-builder-lib/src/electron/electronVersion.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export async function getElectronVersionFromInstalled(projectDir: string) {
3131
for (const name of electronPackages) {
3232
try {
3333
return (await readJson(path.join(projectDir, "node_modules", name, "package.json"))).version
34-
} catch (e) {
34+
} catch (e: any) {
3535
if (e.code !== "ENOENT") {
3636
log.warn({ name, error: e }, `cannot read electron version package.json`)
3737
}
@@ -44,7 +44,7 @@ export async function getElectronPackage(projectDir: string) {
4444
for (const name of electronPackages) {
4545
try {
4646
return await readJson(path.join(projectDir, "node_modules", name, "package.json"))
47-
} catch (e) {
47+
} catch (e: any) {
4848
if (e.code !== "ENOENT") {
4949
log.warn({ name, error: e }, `cannot find electron in package.json`)
5050
}

packages/app-builder-lib/src/publish/BitbucketPublisher.ts

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export class BitbucketPublisher extends HttpPublisher {
4949
hostname: this.hostname,
5050
path: this.basePath,
5151
headers: form.getHeaders(),
52+
timeout: this.info.timeout || undefined,
5253
}
5354
await httpExecutor.doApiRequest(configureRequestOptions(upload, this.auth, "POST"), this.context.cancellationToken, it => form.pipe(it))
5455
return fileName
@@ -59,6 +60,7 @@ export class BitbucketPublisher extends HttpPublisher {
5960
const req: RequestOptions = {
6061
hostname: this.hostname,
6162
path: `${this.basePath}/${filename}`,
63+
timeout: this.info.timeout || undefined,
6264
}
6365
await httpExecutor.request(configureRequestOptions(req, this.auth, "DELETE"), this.context.cancellationToken)
6466
}

packages/app-builder-lib/src/publish/KeygenPublisher.ts

+5
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ export class KeygenPublisher extends HttpPublisher {
139139
headers: {
140140
"Content-Length": dataLength,
141141
},
142+
timeout: this.info.timeout || undefined,
142143
}
143144

144145
await httpExecutor.doApiRequest(configureRequestOptions(upload, null, "PUT"), this.context.cancellationToken, requestProcessor)
@@ -154,6 +155,7 @@ export class KeygenPublisher extends HttpPublisher {
154155
"Keygen-Version": "1.1",
155156
Prefer: "no-redirect",
156157
},
158+
timeout: this.info.timeout || undefined,
157159
}
158160

159161
const data: RecursivePartial<KeygenArtifact> = {
@@ -211,6 +213,7 @@ export class KeygenPublisher extends HttpPublisher {
211213
Accept: "application/vnd.api+json",
212214
"Keygen-Version": "1.1",
213215
},
216+
timeout: this.info.timeout || undefined,
214217
}
215218

216219
return parseJson(httpExecutor.request(configureRequestOptions(req, this.auth, "GET"), this.context.cancellationToken, null))
@@ -225,6 +228,7 @@ export class KeygenPublisher extends HttpPublisher {
225228
Accept: "application/vnd.api+json",
226229
"Keygen-Version": "1.1",
227230
},
231+
timeout: this.info.timeout || undefined,
228232
}
229233

230234
const data: RecursivePartial<KeygenRelease> = {
@@ -257,6 +261,7 @@ export class KeygenPublisher extends HttpPublisher {
257261
Accept: "application/vnd.api+json",
258262
"Keygen-Version": "1.1",
259263
},
264+
timeout: this.info.timeout || undefined,
260265
}
261266
await httpExecutor.request(configureRequestOptions(req, this.auth, "DELETE"), this.context.cancellationToken)
262267
}

packages/app-builder-lib/src/publish/PublishManager.ts

+4
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ export class PublishManager implements PublishContext {
167167
return
168168
}
169169

170+
if (publishConfig.timeout) {
171+
event.timeout = publishConfig.timeout
172+
}
173+
170174
this.taskManager.addTask(publisher.upload(event))
171175
}
172176

packages/builder-util-runtime/src/httpExecutor.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ export abstract class HttpExecutor<T extends Request> {
111111
const request = this.createRequest(options, (response: any) => {
112112
try {
113113
this.handleResponse(response, options, cancellationToken, resolve, reject, redirectCount, requestProcessor)
114-
} catch (e) {
114+
} catch (e: any) {
115115
reject(e)
116116
}
117117
})
118-
this.addErrorAndTimeoutHandlers(request, reject)
118+
this.addErrorAndTimeoutHandlers(request, reject, options.timeout)
119119
this.addRedirectHandlers(request, options, reject, redirectCount, options => {
120120
this.doApiRequest(options, cancellationToken, requestProcessor, redirectCount).then(resolve).catch(reject)
121121
})
@@ -130,8 +130,8 @@ export abstract class HttpExecutor<T extends Request> {
130130
// not required for NodeJS
131131
}
132132

133-
addErrorAndTimeoutHandlers(request: any, reject: (error: Error) => void) {
134-
this.addTimeOutHandler(request, reject)
133+
addErrorAndTimeoutHandlers(request: any, reject: (error: Error) => void, timeout = 60 * 1000) {
134+
this.addTimeOutHandler(request, reject, timeout)
135135
request.on("error", reject)
136136
request.on("aborted", () => {
137137
reject(new Error("Request has been aborted by the server"))
@@ -213,7 +213,7 @@ Please double check that your authentication token is correct. Due to security r
213213
}
214214

215215
// noinspection JSUnusedLocalSymbols
216-
abstract createRequest(options: any, callback: (response: any) => void): T
216+
abstract createRequest(options: RequestOptions, callback: (response: any) => void): T
217217

218218
async downloadToBuffer(url: URL, options: DownloadOptions): Promise<Buffer> {
219219
return await options.cancellationToken.createPromise<Buffer>((resolve, reject, onCancel) => {
@@ -313,7 +313,7 @@ Please double check that your authentication token is correct. Due to security r
313313
options.responseHandler(response, options.callback)
314314
}
315315
})
316-
this.addErrorAndTimeoutHandlers(request, options.callback)
316+
this.addErrorAndTimeoutHandlers(request, options.callback, requestOptions.timeout)
317317
this.addRedirectHandlers(request, requestOptions, options.callback, redirectCount, requestOptions => {
318318
this.doDownload(requestOptions, options, redirectCount++)
319319
})
@@ -324,9 +324,9 @@ Please double check that your authentication token is correct. Due to security r
324324
return new Error(`Too many redirects (> ${this.maxRedirects})`)
325325
}
326326

327-
private addTimeOutHandler(request: any, callback: (error: Error) => void) {
327+
private addTimeOutHandler(request: any, callback: (error: Error) => void, timeout: number) {
328328
request.on("socket", (socket: Socket) => {
329-
socket.setTimeout(60 * 1000, () => {
329+
socket.setTimeout(timeout, () => {
330330
request.abort()
331331
callback(new Error("Request timed out"))
332332
})

packages/builder-util-runtime/src/publishOptions.ts

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ export interface PublishConfiguration {
4646
* Any custom request headers
4747
*/
4848
readonly requestHeaders?: OutgoingHttpHeaders
49+
50+
/**
51+
* Request timeout in milliseconds. (Default is 2 minutes; O is ignored)
52+
*
53+
* @default 60000
54+
*/
55+
readonly timeout?: number | null
4956
}
5057

5158
// https://github.com/electron-userland/electron-builder/issues/3261

packages/electron-publish/src/gitHubPublisher.ts

+2
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ export class GitHubPublisher extends HttpPublisher {
191191
"Content-Type": mime.getType(fileName) || "application/octet-stream",
192192
"Content-Length": dataLength,
193193
},
194+
timeout: this.info.timeout || undefined,
194195
},
195196
this.token
196197
),
@@ -277,6 +278,7 @@ export class GitHubPublisher extends HttpPublisher {
277278
port: baseUrl.port as any,
278279
path: this.info.host != null && this.info.host !== "github.com" ? `/api/v3${path.startsWith("/") ? path : `/${path}`}` : path,
279280
headers: { accept: "application/vnd.github.v3+json" },
281+
timeout: this.info.timeout || undefined,
280282
},
281283
token,
282284
method

0 commit comments

Comments
 (0)