@tramvai/module-request-limiter 1.89.1 → 1.90.4
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/lib/requestLimiter.d.ts +9 -4
- package/lib/server.es.js +22 -16
- package/lib/server.js +23 -16
- package/package.json +6 -8
package/lib/requestLimiter.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { FastifyRequest, FastifyReply, HookHandlerDoneFunction } from 'fastify';
|
|
2
3
|
export interface RequestLimiterOptions {
|
|
3
4
|
limit?: number;
|
|
4
5
|
queue?: number;
|
|
@@ -9,9 +10,9 @@ export interface RequestLimiterOptions {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
export interface RequestLimiterRequest {
|
|
12
|
-
req:
|
|
13
|
-
res:
|
|
14
|
-
next:
|
|
13
|
+
req: FastifyRequest;
|
|
14
|
+
res: FastifyReply;
|
|
15
|
+
next: HookHandlerDoneFunction;
|
|
15
16
|
}
|
|
16
17
|
export declare class RequestLimiter {
|
|
17
18
|
private currentActive;
|
|
@@ -24,8 +25,12 @@ export declare class RequestLimiter {
|
|
|
24
25
|
private maxEventLoopDelay;
|
|
25
26
|
private eventLoopHistogram;
|
|
26
27
|
constructor(options?: RequestLimiterOptions);
|
|
28
|
+
onResponse(): void;
|
|
27
29
|
private nextTick;
|
|
28
30
|
add(request: RequestLimiterRequest): void;
|
|
29
31
|
private loop;
|
|
30
32
|
private run;
|
|
31
33
|
}
|
|
34
|
+
export declare const fastifyRequestsLimiter: import("fastify").FastifyPluginAsync<{
|
|
35
|
+
requestsLimiter: RequestLimiter;
|
|
36
|
+
}, import("http").Server>;
|
package/lib/server.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __decorate } from 'tslib';
|
|
2
2
|
import { Module, provide, Scope } from '@tramvai/core';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import { WEB_FASTIFY_APP_LIMITER_TOKEN, WEB_FASTIFY_APP_TOKEN } from '@tramvai/tokens-server-private';
|
|
4
|
+
import fp from 'fastify-plugin';
|
|
5
5
|
import { HttpError } from '@tinkoff/errors';
|
|
6
6
|
import { monitorEventLoopDelay } from 'perf_hooks';
|
|
7
7
|
import { createToken } from '@tinkoff/dippy';
|
|
@@ -89,7 +89,11 @@ class RequestLimiter {
|
|
|
89
89
|
const timer = setInterval(() => this.nextTick(), 1000);
|
|
90
90
|
timer.unref();
|
|
91
91
|
}
|
|
92
|
-
|
|
92
|
+
onResponse() {
|
|
93
|
+
this.currentActive--;
|
|
94
|
+
this.loop();
|
|
95
|
+
}
|
|
96
|
+
// General idea is change limits every second. Because if DDOS was happened we need some time to get problem with event loop. And better if we slowly adapt
|
|
93
97
|
nextTick() {
|
|
94
98
|
this.eventLoopDelay = Math.max(0, this.eventLoopHistogram.mean / 1e6 - resolution);
|
|
95
99
|
if (Number.isNaN(this.eventLoopDelay))
|
|
@@ -122,16 +126,19 @@ class RequestLimiter {
|
|
|
122
126
|
this.run(this.queue.pop());
|
|
123
127
|
}
|
|
124
128
|
}
|
|
125
|
-
run({
|
|
129
|
+
run({ next }) {
|
|
126
130
|
this.currentActive++;
|
|
127
|
-
// onFinished doesn't work OK in DEV mode. Just stuck with high load without any reasons
|
|
128
|
-
onFinished(res, () => {
|
|
129
|
-
this.currentActive--;
|
|
130
|
-
this.loop();
|
|
131
|
-
});
|
|
132
131
|
next();
|
|
133
132
|
}
|
|
134
133
|
}
|
|
134
|
+
const fastifyRequestsLimiter = fp(async (fastify, { requestsLimiter }) => {
|
|
135
|
+
fastify.addHook('onRequest', (req, res, next) => {
|
|
136
|
+
requestsLimiter.add({ req, res, next });
|
|
137
|
+
});
|
|
138
|
+
fastify.addHook('onResponse', async () => {
|
|
139
|
+
requestsLimiter.onResponse();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
135
142
|
|
|
136
143
|
const REQUESTS_LIMITER_TOKEN = createToken('requestsLimiterToken');
|
|
137
144
|
const REQUESTS_LIMITER_ACTIVATE_TOKEN = createToken('requestsLimiterActivateToken');
|
|
@@ -157,19 +164,18 @@ RequestLimiterModule = __decorate([
|
|
|
157
164
|
},
|
|
158
165
|
}),
|
|
159
166
|
provide({
|
|
160
|
-
provide:
|
|
167
|
+
provide: WEB_FASTIFY_APP_LIMITER_TOKEN,
|
|
161
168
|
multi: true,
|
|
162
|
-
useFactory: ({ requestsLimiter, featureEnable }) => {
|
|
163
|
-
return
|
|
169
|
+
useFactory: ({ app, requestsLimiter, featureEnable }) => {
|
|
170
|
+
return async () => {
|
|
164
171
|
if (featureEnable !== true) {
|
|
165
172
|
return;
|
|
166
173
|
}
|
|
167
|
-
app.
|
|
168
|
-
requestsLimiter.add({ req, res, next });
|
|
169
|
-
});
|
|
174
|
+
await app.register(fastifyRequestsLimiter, { requestsLimiter });
|
|
170
175
|
};
|
|
171
176
|
},
|
|
172
177
|
deps: {
|
|
178
|
+
app: WEB_FASTIFY_APP_TOKEN,
|
|
173
179
|
requestsLimiter: REQUESTS_LIMITER_TOKEN,
|
|
174
180
|
featureEnable: { token: REQUESTS_LIMITER_ACTIVATE_TOKEN, optional: true },
|
|
175
181
|
},
|
|
@@ -178,4 +184,4 @@ RequestLimiterModule = __decorate([
|
|
|
178
184
|
})
|
|
179
185
|
], RequestLimiterModule);
|
|
180
186
|
|
|
181
|
-
export { REQUESTS_LIMITER_ACTIVATE_TOKEN, REQUESTS_LIMITER_OPTIONS_TOKEN, REQUESTS_LIMITER_TOKEN, RequestLimiter, RequestLimiterModule };
|
|
187
|
+
export { REQUESTS_LIMITER_ACTIVATE_TOKEN, REQUESTS_LIMITER_OPTIONS_TOKEN, REQUESTS_LIMITER_TOKEN, RequestLimiter, RequestLimiterModule, fastifyRequestsLimiter };
|
package/lib/server.js
CHANGED
|
@@ -4,15 +4,15 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var tslib = require('tslib');
|
|
6
6
|
var core = require('@tramvai/core');
|
|
7
|
-
var
|
|
8
|
-
var
|
|
7
|
+
var tokensServerPrivate = require('@tramvai/tokens-server-private');
|
|
8
|
+
var fp = require('fastify-plugin');
|
|
9
9
|
var errors = require('@tinkoff/errors');
|
|
10
10
|
var perf_hooks = require('perf_hooks');
|
|
11
11
|
var dippy = require('@tinkoff/dippy');
|
|
12
12
|
|
|
13
13
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var fp__default = /*#__PURE__*/_interopDefaultLegacy(fp);
|
|
16
16
|
|
|
17
17
|
class DoubleLinkedList {
|
|
18
18
|
constructor() {
|
|
@@ -97,7 +97,11 @@ class RequestLimiter {
|
|
|
97
97
|
const timer = setInterval(() => this.nextTick(), 1000);
|
|
98
98
|
timer.unref();
|
|
99
99
|
}
|
|
100
|
-
|
|
100
|
+
onResponse() {
|
|
101
|
+
this.currentActive--;
|
|
102
|
+
this.loop();
|
|
103
|
+
}
|
|
104
|
+
// General idea is change limits every second. Because if DDOS was happened we need some time to get problem with event loop. And better if we slowly adapt
|
|
101
105
|
nextTick() {
|
|
102
106
|
this.eventLoopDelay = Math.max(0, this.eventLoopHistogram.mean / 1e6 - resolution);
|
|
103
107
|
if (Number.isNaN(this.eventLoopDelay))
|
|
@@ -130,16 +134,19 @@ class RequestLimiter {
|
|
|
130
134
|
this.run(this.queue.pop());
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
|
-
run({
|
|
137
|
+
run({ next }) {
|
|
134
138
|
this.currentActive++;
|
|
135
|
-
// onFinished doesn't work OK in DEV mode. Just stuck with high load without any reasons
|
|
136
|
-
onFinished__default["default"](res, () => {
|
|
137
|
-
this.currentActive--;
|
|
138
|
-
this.loop();
|
|
139
|
-
});
|
|
140
139
|
next();
|
|
141
140
|
}
|
|
142
141
|
}
|
|
142
|
+
const fastifyRequestsLimiter = fp__default["default"](async (fastify, { requestsLimiter }) => {
|
|
143
|
+
fastify.addHook('onRequest', (req, res, next) => {
|
|
144
|
+
requestsLimiter.add({ req, res, next });
|
|
145
|
+
});
|
|
146
|
+
fastify.addHook('onResponse', async () => {
|
|
147
|
+
requestsLimiter.onResponse();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
143
150
|
|
|
144
151
|
const REQUESTS_LIMITER_TOKEN = dippy.createToken('requestsLimiterToken');
|
|
145
152
|
const REQUESTS_LIMITER_ACTIVATE_TOKEN = dippy.createToken('requestsLimiterActivateToken');
|
|
@@ -165,19 +172,18 @@ exports.RequestLimiterModule = tslib.__decorate([
|
|
|
165
172
|
},
|
|
166
173
|
}),
|
|
167
174
|
core.provide({
|
|
168
|
-
provide:
|
|
175
|
+
provide: tokensServerPrivate.WEB_FASTIFY_APP_LIMITER_TOKEN,
|
|
169
176
|
multi: true,
|
|
170
|
-
useFactory: ({ requestsLimiter, featureEnable }) => {
|
|
171
|
-
return
|
|
177
|
+
useFactory: ({ app, requestsLimiter, featureEnable }) => {
|
|
178
|
+
return async () => {
|
|
172
179
|
if (featureEnable !== true) {
|
|
173
180
|
return;
|
|
174
181
|
}
|
|
175
|
-
app.
|
|
176
|
-
requestsLimiter.add({ req, res, next });
|
|
177
|
-
});
|
|
182
|
+
await app.register(fastifyRequestsLimiter, { requestsLimiter });
|
|
178
183
|
};
|
|
179
184
|
},
|
|
180
185
|
deps: {
|
|
186
|
+
app: tokensServerPrivate.WEB_FASTIFY_APP_TOKEN,
|
|
181
187
|
requestsLimiter: REQUESTS_LIMITER_TOKEN,
|
|
182
188
|
featureEnable: { token: REQUESTS_LIMITER_ACTIVATE_TOKEN, optional: true },
|
|
183
189
|
},
|
|
@@ -190,3 +196,4 @@ exports.REQUESTS_LIMITER_ACTIVATE_TOKEN = REQUESTS_LIMITER_ACTIVATE_TOKEN;
|
|
|
190
196
|
exports.REQUESTS_LIMITER_OPTIONS_TOKEN = REQUESTS_LIMITER_OPTIONS_TOKEN;
|
|
191
197
|
exports.REQUESTS_LIMITER_TOKEN = REQUESTS_LIMITER_TOKEN;
|
|
192
198
|
exports.RequestLimiter = RequestLimiter;
|
|
199
|
+
exports.fastifyRequestsLimiter = fastifyRequestsLimiter;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-request-limiter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.90.4",
|
|
4
4
|
"description": "Enable different rendering modes for pages",
|
|
5
5
|
"main": "lib/server.js",
|
|
6
6
|
"module": "lib/server.es.js",
|
|
@@ -25,16 +25,14 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@tinkoff/errors": "0.2.20",
|
|
28
|
-
"
|
|
29
|
-
},
|
|
30
|
-
"devDependencies": {
|
|
31
|
-
"@types/express": "^4.17.9"
|
|
28
|
+
"fastify-plugin": "^3.0.1"
|
|
32
29
|
},
|
|
30
|
+
"devDependencies": {},
|
|
33
31
|
"peerDependencies": {
|
|
34
32
|
"@tinkoff/dippy": "0.7.39",
|
|
35
|
-
"@tramvai/core": "1.
|
|
36
|
-
"@tramvai/tokens-server": "1.
|
|
37
|
-
"
|
|
33
|
+
"@tramvai/core": "1.90.4",
|
|
34
|
+
"@tramvai/tokens-server-private": "1.90.4",
|
|
35
|
+
"fastify": "^3.0.0",
|
|
38
36
|
"tslib": "^2.0.3"
|
|
39
37
|
}
|
|
40
38
|
}
|