@ndiinginc/router 4.6.1 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -16
- package/package.json +3 -3
- package/src/app.js +2 -2
- package/src/response.js +2 -2
- package/src/router.js +2 -2
package/README.md
CHANGED
|
@@ -198,18 +198,18 @@ Jika tidak ada handler yang mengirim response, router mengirim JSON otomatis:
|
|
|
198
198
|
|
|
199
199
|
## Timeout
|
|
200
200
|
|
|
201
|
-
Aktifkan lewat opsi `
|
|
201
|
+
Aktifkan lewat opsi `requestTimeout` (milidetik) pada `App`. Jika seluruh chain handler melebihi waktu tersebut, error `504 Gateway Timeout` dilempar dan diteruskan ke error handler.
|
|
202
202
|
|
|
203
203
|
```js
|
|
204
|
-
const app = new App({
|
|
204
|
+
const app = new App({ requestTimeout: 5000 });
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
- Tanpa opsi `
|
|
207
|
+
- Tanpa opsi `requestTimeout` (atau bernilai `0`), tidak ada batas waktu
|
|
208
208
|
- Handler yang sudah berjalan tidak dihentikan paksa. Tetapi setelah response dikirim, `res.json()` dan `res.send()` mengabaikan penulisan berikutnya, dan handler selanjutnya di chain tidak dipanggil
|
|
209
209
|
|
|
210
210
|
### `req.signal`
|
|
211
211
|
|
|
212
|
-
Saat `
|
|
212
|
+
Saat `requestTimeout` aktif, `req.signal` adalah `AbortSignal` yang di-abort ketika timeout terjadi (reason-nya error 504) atau ketika salah satu handler melempar error (reason-nya error tersebut). Teruskan ke operasi yang mendukungnya agar pekerjaan ikut dibatalkan:
|
|
213
213
|
|
|
214
214
|
```js
|
|
215
215
|
app.get("/proxy", async (req, res) => {
|
|
@@ -218,7 +218,7 @@ app.get("/proxy", async (req, res) => {
|
|
|
218
218
|
});
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
`req.signal` bernilai `undefined` jika `
|
|
221
|
+
`req.signal` bernilai `undefined` jika `requestTimeout` tidak diaktifkan.
|
|
222
222
|
|
|
223
223
|
## Request
|
|
224
224
|
|
|
@@ -228,7 +228,7 @@ app.get("/proxy", async (req, res) => {
|
|
|
228
228
|
| `req.query` | Object query string, di-parse secara lazy. Key yang berulang menjadi array, dan `+` di-decode menjadi spasi |
|
|
229
229
|
| `req.params` | Parameter dari route dinamis (sudah di-decode) |
|
|
230
230
|
| `req.body` | Hasil parse body (butuh middleware `json()`) |
|
|
231
|
-
| `req.signal` | `AbortSignal` yang di-abort saat timeout atau error handler (hanya jika `
|
|
231
|
+
| `req.signal` | `AbortSignal` yang di-abort saat timeout atau error handler (hanya jika `requestTimeout` aktif) |
|
|
232
232
|
|
|
233
233
|
```js
|
|
234
234
|
// GET /search?tag=a&tag=b&page=2
|
|
@@ -310,21 +310,21 @@ Perilaku:
|
|
|
310
310
|
## Opsi
|
|
311
311
|
|
|
312
312
|
```js
|
|
313
|
-
const app = new App({
|
|
313
|
+
const app = new App({ cacheSize: 1000, requestTimeout: 5000 });
|
|
314
314
|
```
|
|
315
315
|
|
|
316
316
|
| Opsi | Default | Keterangan |
|
|
317
317
|
| --- | --- | --- |
|
|
318
|
-
| `
|
|
319
|
-
| `
|
|
318
|
+
| `cacheSize` | `1000` | Jumlah maksimum entri LRU cache untuk hasil lookup `METHOD path` |
|
|
319
|
+
| `requestTimeout` | - | Batas waktu handler dalam ms (khusus `App`). Lihat bagian [Timeout](#requestTimeout) |
|
|
320
320
|
|
|
321
|
-
`Router` hanya menerima `
|
|
321
|
+
`Router` hanya menerima `cacheSize`.
|
|
322
322
|
|
|
323
323
|
## API
|
|
324
324
|
|
|
325
325
|
### `new App([options])` / `new Router([options])`
|
|
326
326
|
|
|
327
|
-
Membuat instance baru. `App` adalah `Router` ditambah `listen()` dan dukungan `
|
|
327
|
+
Membuat instance baru. `App` adalah `Router` ditambah `listen()` dan dukungan `requestTimeout`.
|
|
328
328
|
|
|
329
329
|
### `router.use([path], ...handlers | router)`
|
|
330
330
|
|
|
@@ -355,11 +355,12 @@ console.log(server.address().port);
|
|
|
355
355
|
|
|
356
356
|
Hello world dengan satu route `GET /`, diuji memakai `autocannon -c 100 -d 40 -p 10` di mesin lokal.
|
|
357
357
|
|
|
358
|
-
| | Req/
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
|
|
|
362
|
-
|
|
|
358
|
+
| package | Latency | Req/Sec | Bytes/Sec | Result |
|
|
359
|
+
| ----------------- | -------- | -------- | --------- | ------------------------------------- |
|
|
360
|
+
| fastify | 25.3 ms | 38,738.4 | 7.24 MB | 1550k requests in 40.06s, 290 MB read |
|
|
361
|
+
| @ndiinginc/router | 28.45 ms | 34,541.4 | 5.91 MB | 1383k requests in 40.06s, 236 MB read |
|
|
362
|
+
| express | 41 ms | 24,095.6 | 6.05 MB | 965k requests in 40.06s, 242 MB read |
|
|
363
|
+
|
|
363
364
|
|
|
364
365
|
Hasil bervariasi tergantung mesin, versi Node.js, dan jumlah route. Benchmark ini hanya menggambarkan overhead dasar, bukan performa aplikasi nyata.
|
|
365
366
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ndiinginc/router",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"type": "commonjs",
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@ndiinginc/commit": "^1.0.1",
|
|
22
|
-
"@ndiinginc/test": "^1.
|
|
22
|
+
"@ndiinginc/test": "^1.7.1",
|
|
23
23
|
"@types/jest": "^30.0.0",
|
|
24
|
-
"@types/node": "^26.6.
|
|
24
|
+
"@types/node": "^26.6.5"
|
|
25
25
|
}
|
|
26
26
|
}
|
package/src/app.js
CHANGED
|
@@ -19,7 +19,7 @@ class App extends Router {
|
|
|
19
19
|
|
|
20
20
|
const timeout = setTimeout(() => {
|
|
21
21
|
controller.abort(ErrorResponse.status(504));
|
|
22
|
-
}, this.
|
|
22
|
+
}, this.requestTimeout);
|
|
23
23
|
|
|
24
24
|
let handleAbort;
|
|
25
25
|
const timeoutPromise = new Promise((_, reject) => {
|
|
@@ -54,7 +54,7 @@ class App extends Router {
|
|
|
54
54
|
await handler(req, res);
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
|
-
if (this.
|
|
57
|
+
if (this.requestTimeout) await this.withTimeout(req, handlerPromise);
|
|
58
58
|
else await handlerPromise();
|
|
59
59
|
} catch (error) {
|
|
60
60
|
err = error;
|
package/src/response.js
CHANGED
|
@@ -7,7 +7,7 @@ class Response extends http.ServerResponse {
|
|
|
7
7
|
}
|
|
8
8
|
send(chunk) {
|
|
9
9
|
if (this.writableEnded) return;
|
|
10
|
-
this.end(chunk)
|
|
10
|
+
this.end(chunk,null,null);//avoid ArgumentsAdaptorTrampoline from V8
|
|
11
11
|
}
|
|
12
12
|
json(value) {
|
|
13
13
|
if (this.writableEnded) return;
|
|
@@ -16,7 +16,7 @@ class Response extends http.ServerResponse {
|
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
this.setHeader("Content-Type", "application/json");
|
|
19
|
-
this.end(JSON.stringify(value))
|
|
19
|
+
this.end(JSON.stringify(value),null,null);//avoid ArgumentsAdaptorTrampoline from V8
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
exports.Response = Response;
|
package/src/router.js
CHANGED
|
@@ -4,8 +4,8 @@ const { decodePathParam } = require("./util.js");
|
|
|
4
4
|
|
|
5
5
|
class Router {
|
|
6
6
|
constructor(options = {}) {
|
|
7
|
-
this.
|
|
8
|
-
this.cacheSize = options.
|
|
7
|
+
this.requestTimeout = options.requestTimeout ?? 0;
|
|
8
|
+
this.cacheSize = options.cacheSize ?? 1000;
|
|
9
9
|
this.root = new Node();
|
|
10
10
|
this.seq = 0;
|
|
11
11
|
this.cache = new Cache(this.cacheSize);
|