@withjoy/limiter 0.0.9 → 0.1.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 CHANGED
@@ -1,4 +1,4 @@
1
- ### A wrapper for limitd and limitdctl
1
+ ### A wrapper for limitd-redis
2
2
 
3
3
  ##### Why ?
4
4
 
@@ -7,16 +7,10 @@ Provides utilities and rollback functionality for our clients.
7
7
  ### Testing:
8
8
 
9
9
  `npm run test` will run offline tests using a mock.
10
- `npm run sanity-check` will run against a limitd service configured to run with the config at `/tests/limitd.config`.
10
+ `npm run sanity-check` will run against a limitd service configured to run with the test buckets.
11
11
 
12
- ##### How can I run that limitd instance quickly ?
13
-
14
- check [the Wiki](https://withjoy.atlassian.net/wiki/spaces/KNOW/pages/1905557728/Running+withjoy+limitd+locally)
15
-
16
- run this in the root of this repo:
12
+ ## Quick Test
17
13
  ```bash
18
- docker run -p 9231:9231 \
19
- --mount \
20
- type=bind,source="$(pwd)"/tests/limitd.config,target=/etc/limitd.config \
21
- -it joylife/limitd:release-6-d5e4805
14
+ node tests/performTestWithTestPerMinute.js
15
+
22
16
  ```
package/limiter.js CHANGED
@@ -1,10 +1,24 @@
1
1
  "use strict";
2
2
 
3
-
4
- var LimitdClient = require("limitd-client");
3
+ var LimitdRedis = require("limitd-redis"); // name to redis matter
4
+
5
+ const defaultBuckets = {
6
+ emailsByEventId: { size: 3000 },
7
+ emailsByEventIdRate: { size: 500, per_hour: 500 },
8
+ emailsByEventId_Warn: { size: 1000 },
9
+ emailsByEventIdRate_Warn: { size: 200, per_hour: 200 },
10
+ eventsByUserId: { size: 5, per_hour: 5 },
11
+ eventsByIpRate: { size: 240, per_hour: 240 },
12
+ paymentAttempts: { size: 9000 },
13
+ paymentAttemptsByReceiverId: { size: 900 },
14
+ // for development testing
15
+ testPerMinute: { size: 3, per_minute: 1 },
16
+ };
17
+
18
+ const defaultRedisKeyPrefix = "limitdRedis:";
5
19
 
6
20
  class Operation {
7
- constructor({opname,type,id,amount}){
21
+ constructor({ opname, type, id, amount }) {
8
22
  this.opname = opname;
9
23
  this.type = type;
10
24
  this.id = id;
@@ -24,12 +38,11 @@ class Operation {
24
38
  let connection = null;
25
39
 
26
40
  class Limiter {
27
-
28
41
  constructor(config) {
29
42
  this._console = config.console;
43
+ this._config = config;
30
44
  this._operationList = [];
31
- this._limitd = undefined;
32
- this.connect(config.limitdUrl);
45
+ this._limitdRedis = this.connect();
33
46
  }
34
47
 
35
48
  /*
@@ -37,11 +50,21 @@ class Limiter {
37
50
  and we invoke this method from the Constructor.
38
51
  stub it to prevent a real connect from happening under Test Suite Conditions
39
52
  */
40
- connect(url) {
41
- if(!connection) {
42
- connection = new LimitdClient(url);
53
+ connect() {
54
+ let buckets = this._config.buckets || {};
55
+ buckets = {
56
+ ...defaultBuckets,
57
+ ...buckets,
58
+ };
59
+ const keyPrefix = this._config.keyPrefix || defaultRedisKeyPrefix;
60
+ if (!connection) {
61
+ connection = new LimitdRedis({
62
+ uri: this._config.limitdUrl,
63
+ buckets,
64
+ keyPrefix,
65
+ });
43
66
  }
44
- this._limitd = connection;
67
+ this._limitdRedis = connection;
45
68
  return connection;
46
69
  }
47
70
 
@@ -49,16 +72,16 @@ class Limiter {
49
72
  Go through the log of things we did and do the opposite
50
73
  */
51
74
  revert() {
52
- let ops = this._operationList.map(op => op.clone());
75
+ let ops = this._operationList.map((op) => op.clone());
53
76
  this._operationList = [];
54
77
 
55
78
  let p = Promise.resolve();
56
79
  for (let op of ops) {
57
80
  switch (op.opname) {
58
- case 'put':
81
+ case "put":
59
82
  p = p.then(() => this._take(op.type, op.id, op.amount));
60
83
  break;
61
- case 'take':
84
+ case "take":
62
85
  p = p.then(() => this._put(op.type, op.id, op.amount));
63
86
  break;
64
87
  }
@@ -71,24 +94,36 @@ class Limiter {
71
94
  this._operationList.push(op);
72
95
  }
73
96
 
97
+ close() {
98
+ return new Promise((resolve, reject) => {
99
+ this._limitdRedis.close((err, resp) => {
100
+ if (err) {
101
+ this._console.error(err);
102
+ return reject(err);
103
+ }
104
+ console.log("Connection closed");
105
+ resolve(resp);
106
+ });
107
+ });
108
+ }
74
109
  // promise wrapper for limitd lib put
75
- _put (type, id, amount) {
110
+ _put(type, id, amount) {
76
111
  return new Promise((resolve, reject) =>
77
- this._limitd.put(type, id, amount, (err, resp) => {
112
+ this._limitdRedis.put(type, id, amount, (err, resp) => {
78
113
  if (err) {
79
114
  this._console.error(err);
80
115
  return reject(err);
81
116
  }
82
- this.record(new Operation({opname: "put",type,id,amount}));
83
- resolve(null);
117
+ this.record(new Operation({ opname: "put", type, id, amount }));
118
+ resolve(resp);
84
119
  })
85
120
  );
86
121
  }
87
122
 
88
123
  // promise wrapper for limitd lib take
89
- _take (type, id, amount) {
124
+ _take(type, id, amount) {
90
125
  return new Promise((resolve, reject) =>
91
- this._limitd.take(type, id, amount, (err, resp) => {
126
+ this._limitdRedis.take(type, id, amount, (err, resp) => {
92
127
  if (err) {
93
128
  this._console.error(err);
94
129
  return reject(err);
@@ -99,10 +134,10 @@ class Limiter {
99
134
  return reject(new Error("Non Conformant"));
100
135
  }
101
136
 
102
- this.record(new Operation({opname: "take",type,id,amount}));
103
- return resolve(null);
137
+ this.record(new Operation({ opname: "take", type, id, amount }));
138
+ return resolve(resp);
104
139
  })
105
- )
140
+ );
106
141
  }
107
142
 
108
143
  transfer(type, id, amount) {
@@ -112,17 +147,20 @@ class Limiter {
112
147
 
113
148
  this._console.info(`Transfering ${amount} from ${type}-${id}`);
114
149
  // If amount == 0, there is nothing to do
115
- if (amount == 0) { return Promise.resolve(null); }
116
- if (amount < 0) { return this._put(type, id, -amount); }
150
+ if (amount == 0) {
151
+ return Promise.resolve(null);
152
+ }
153
+ if (amount < 0) {
154
+ return this._put(type, id, -amount);
155
+ }
117
156
  return this._take(type, id, amount);
118
157
  }
119
158
 
120
159
  transferAll(arr) {
121
160
  return Promise.all(
122
- arr.map(spec => this.transfer(spec[0], spec[1], spec[2]))
123
- ).then(() => null);
161
+ arr.map((spec) => this.transfer(spec[0], spec[1], spec[2]))
162
+ );
124
163
  }
125
164
  }
126
165
 
127
-
128
166
  module.exports = Limiter;
package/package.json CHANGED
@@ -1,21 +1,19 @@
1
1
  {
2
2
  "name": "@withjoy/limiter",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "description": "Api Rate limiter",
5
5
  "main": "limiter.js",
6
6
  "scripts": {
7
- "test": "jest",
7
+ "test": "NODE_ENV=test node --expose-gc --max-old-space-size=6144 node_modules/.bin/jest --logHeapUsage -i --forceExit",
8
8
  "sanity-check": "node tests/sanityCheck.js k 10"
9
9
  },
10
10
  "author": "services@withjoy.com",
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
- "limitd-client": "^2.9.1"
13
+ "limitd-redis": "^5.1.1"
14
14
  },
15
15
  "devDependencies": {
16
- "jest": "^24.9.0",
17
- "limitd": "^5.3.0",
18
- "limitdctl": "^1.1.1"
16
+ "jest": "^24.9.0"
19
17
  },
20
18
  "directories": {
21
19
  "test": "tests"
@@ -1,212 +1,270 @@
1
- const Limiter = require('../limiter');
1
+ const Limiter = require("../limiter");
2
2
 
3
3
  const PUT_FAILED = "Failed to put!";
4
4
  const TAKE_FAILED = "Failed to take!";
5
+
6
+ const TEST_BUCKETS = {
7
+ emails: {
8
+ size: 10,
9
+ },
10
+ emailRate: {
11
+ size: 10,
12
+ per_hour: 10,
13
+ },
14
+ };
5
15
  /*
6
16
  The limitd service is essentially a token bank
7
17
  that we can withdraw from (take) or deposit to (put)
8
18
  */
9
19
  const limiterWithMockService = (succeeds = true, conforms = true) => {
10
- let token_pile = 0;
11
- const limiter = new Limiter({ console: console });
12
-
13
- limiter._limitd = (new class MockLimitd {
14
- constructor(should_succeed, should_conform) {
15
- this.should_succeed = should_succeed;
16
- this.should_conform = should_conform;
17
- }
18
- put(type, id, amount, callback) {
19
- console.log("called put", type, id, amount);
20
- console.log(this.should_succeed)
21
- if(!this.should_succeed){
22
- return callback(new Error(PUT_FAILED), "This is not falsey");
23
- }
24
- token_pile += amount;
25
- callback(null, {})
26
- }
27
- take(type, id, amount, callback) {
28
- console.log("called take", type, id, amount);
29
- if(!this.should_succeed){
30
- return callback(new Error(TAKE_FAILED), null);
31
- }else if (!this.should_conform) {
32
- return callback(null, {}); // non coformant
33
- }
34
- token_pile -= amount;
35
- callback(null, { conformant: true })
36
- }
37
- _num_tokens(){ return token_pile }
38
- }(succeeds, conforms))
39
- return limiter;
40
- }
41
-
42
- test("Resolves to null if we aren't doing a real transfer", done => {
43
- let limiter = limiterWithMockService();
44
- limiter.transfer("a", "b", 0, null)
45
- .then(result => {
46
- expect(result).toBe(null);
47
- expect(limiter._limitd._num_tokens()).toBe(0);
48
- done();
49
- })
20
+ let token_pile = 0;
21
+ const limiter = new Limiter({
22
+ console: console,
23
+ limitdUrl: "localhost:6379",
24
+ buckets: TEST_BUCKETS,
25
+ });
26
+
27
+ limiter._limitdRedis = new (class MockLimitd {
28
+ constructor(should_succeed, should_conform) {
29
+ this.should_succeed = should_succeed;
30
+ this.should_conform = should_conform;
31
+ }
32
+ put(type, id, amount, callback) {
33
+ console.log("called put", type, id, amount);
34
+ console.log(this.should_succeed);
35
+ if (!this.should_succeed) {
36
+ return callback(new Error(PUT_FAILED), "This is not falsey");
37
+ }
38
+ token_pile += amount;
39
+ callback(null, {});
40
+ }
41
+ take(type, id, amount, callback) {
42
+ console.log("called take", type, id, amount);
43
+ if (!this.should_succeed) {
44
+ return callback(new Error(TAKE_FAILED), null);
45
+ } else if (!this.should_conform) {
46
+ return callback(null, {}); // non coformant
47
+ }
48
+ token_pile -= amount;
49
+ callback(null, { conformant: true });
50
+ }
51
+ _num_tokens() {
52
+ return token_pile;
53
+ }
54
+ })(succeeds, conforms);
55
+ return limiter;
56
+ };
57
+
58
+ test("perfrom limitd-redis testing with test bucket", async (done) => {
59
+ const limiter = new Limiter({
60
+ limitdUrl: "localhost:6379",
61
+ console: console,
62
+ buckets: {
63
+ test: { size: 3, per_second: 2 },
64
+ },
65
+ });
66
+ // take 2 # Conformant - Remaining: 1
67
+ const result1 = await limiter.transfer("test", "test-key", 2);
68
+ expect(result1).toMatchObject({
69
+ conformant: true,
70
+ remaining: 1,
71
+ limit: 3,
72
+ delayed: false,
73
+ });
74
+ await expect(limiter.transfer("test", "test-key", 2)).rejects.toThrow(
75
+ "Non Conformant"
76
+ );
77
+
78
+ // Put 1
79
+ const result3 = await limiter.transfer("test", "test-key", -1);
80
+ expect(result3).toMatchObject({
81
+ remaining: 2,
82
+ limit: 3,
83
+ });
84
+
85
+ //Now Conformant - Remaining: 2
86
+ const result4 = await limiter.transfer("test", "test-key", 2);
87
+ expect(result4).toMatchObject({
88
+ conformant: true,
89
+ remaining: 0,
90
+ limit: 3,
91
+ delayed: false,
92
+ });
93
+ await limiter.close();
94
+ done();
95
+ });
96
+
97
+ test("Resolves to null if we aren't doing a real transfer", (done) => {
98
+ let limiter = limiterWithMockService();
99
+ limiter.transfer("a", "b", 0, null).then((result) => {
100
+ expect(result).toBe(null);
101
+ expect(limiter._limitdRedis._num_tokens()).toBe(0);
102
+ done();
103
+ });
50
104
  });
51
105
 
52
- test("Adds tokens if provided a negative token amount", done => {
53
- let limiter = limiterWithMockService();
54
- limiter.transfer("a", "b", -5)
55
- .then(result => {
56
- expect(result).toBe(null)
57
- expect(limiter._limitd._num_tokens()).toBe(5);
58
- done();
59
- })
106
+ test("Adds tokens if provided a negative token amount", (done) => {
107
+ let limiter = limiterWithMockService();
108
+ limiter.transfer("a", "b", -5).then((result) => {
109
+ expect(result).toMatchObject({});
110
+ expect(limiter._limitdRedis._num_tokens()).toBe(5);
111
+ done();
112
+ });
60
113
  });
61
114
 
62
- test("Removes tokens if provided a positive token amount", done => {
63
- let limiter = limiterWithMockService();
64
- limiter.transfer("a", "b", 5)
65
- .then(result => {
66
- expect(result).toBe(null)
67
- expect(limiter._limitd._num_tokens()).toBe(-5);
68
- done();
69
- })
115
+ test("Removes tokens if provided a positive token amount", (done) => {
116
+ let limiter = limiterWithMockService();
117
+ limiter.transfer("a", "b", 5).then((result) => {
118
+ expect(result).toMatchObject({ conformant: true });
119
+ expect(limiter._limitdRedis._num_tokens()).toBe(-5);
120
+ done();
121
+ });
70
122
  });
71
123
 
72
- test("Reverts all taken tokens when revert is called", done => {
73
- let limiter = limiterWithMockService();
74
- limiter.transfer("a", "b", 5)
75
- .then(result => {
76
- expect(result).toBe(null)
77
- expect(limiter._limitd._num_tokens()).toBe(-5);
78
- })
79
- .then(() => limiter.revert())
80
- .then(() => {
81
- expect(limiter._limitd._num_tokens()).toBe(0);
82
- done();
83
- })
124
+ test("Reverts all taken tokens when revert is called", (done) => {
125
+ let limiter = limiterWithMockService();
126
+ limiter
127
+ .transfer("a", "b", 5)
128
+ .then((result) => {
129
+ expect(result).toMatchObject({ conformant: true });
130
+ expect(limiter._limitdRedis._num_tokens()).toBe(-5);
131
+ })
132
+ .then(() => limiter.revert())
133
+ .then(() => {
134
+ expect(limiter._limitdRedis._num_tokens()).toBe(0);
135
+ done();
136
+ });
84
137
  });
85
138
 
86
- test("Reverts all given tokens when revert is called", done => {
87
- let limiter = limiterWithMockService();
88
- limiter.transfer("a", "b", -5)
89
- .then(result => {
90
- expect(result).toBe(null)
91
- expect(limiter._limitd._num_tokens()).toBe(5);
92
- })
93
- .then(() => limiter.revert())
94
- .then(() => {
95
- expect(limiter._limitd._num_tokens()).toBe(0);
96
- done();
97
- })
139
+ test("Reverts all given tokens when revert is called", (done) => {
140
+ let limiter = limiterWithMockService();
141
+ limiter
142
+ .transfer("a", "b", -5)
143
+ .then((result) => {
144
+ expect(result).toMatchObject({});
145
+ expect(limiter._limitdRedis._num_tokens()).toBe(5);
146
+ })
147
+ .then(() => limiter.revert())
148
+ .then(() => {
149
+ expect(limiter._limitdRedis._num_tokens()).toBe(0);
150
+ done();
151
+ });
98
152
  });
99
153
 
100
- test("Reverts a series of actions when revert is called", done => {
101
- let limiter = limiterWithMockService();
102
- limiter.transfer("a", "b", -5)
103
- .then(result => {
104
- expect(result).toBe(null)
105
- expect(limiter._limitd._num_tokens()).toBe(5);
106
- })
107
- .then(() => limiter.transfer("a", "b", 2))
108
- .then(result => {
109
- expect(result).toBe(null)
110
- expect(limiter._limitd._num_tokens()).toBe(3);
111
- })
112
- .then(() => limiter.revert())
113
- .then(() => {
114
- expect(limiter._limitd._num_tokens()).toBe(0);
115
- done();
116
- })
154
+ test("Reverts a series of actions when revert is called", (done) => {
155
+ let limiter = limiterWithMockService();
156
+ limiter
157
+ .transfer("a", "b", -5)
158
+ .then((result) => {
159
+ expect(result).toMatchObject({});
160
+ expect(limiter._limitdRedis._num_tokens()).toBe(5);
161
+ })
162
+ .then(() => limiter.transfer("a", "b", 2))
163
+ .then((result) => {
164
+ expect(result).toMatchObject({ conformant: true });
165
+ expect(limiter._limitdRedis._num_tokens()).toBe(3);
166
+ })
167
+ .then(() => limiter.revert())
168
+ .then(() => {
169
+ expect(limiter._limitdRedis._num_tokens()).toBe(0);
170
+ done();
171
+ });
117
172
  });
118
173
 
119
- test("Properly executes a transferAll()", done => {
120
- let limiter = limiterWithMockService();
121
- limiter.transferAll([
122
- ["a", "b", -5],
123
- ["a", "b", 2]
124
- ])
125
- .then(result => {
126
- expect(result).toBe(null)
127
- expect(limiter._limitd._num_tokens()).toBe(3);
128
- })
129
- .then(() => limiter.revert())
130
- .then(() => {
131
- expect(limiter._limitd._num_tokens()).toBe(0);
132
- done();
133
- })
174
+ test("Properly executes a transferAll()", (done) => {
175
+ let limiter = limiterWithMockService();
176
+ limiter
177
+ .transferAll([
178
+ ["a", "b", -5],
179
+ ["a", "b", 2],
180
+ ])
181
+ .then((result) => {
182
+ expect(result).toMatchObject([{}, { conformant: true }]);
183
+ expect(limiter._limitdRedis._num_tokens()).toBe(3);
184
+ })
185
+ .then(() => limiter.revert())
186
+ .then(() => {
187
+ expect(limiter._limitdRedis._num_tokens()).toBe(0);
188
+ done();
189
+ });
134
190
  });
135
191
 
136
192
  test("Errors from the underlying service are propagated (put)", () => {
137
- let limiter = limiterWithMockService(succeeds=false);
138
- let endsInFailure = limiter.transfer("a", "b", -5);
139
- return expect(endsInFailure).rejects.toThrow(PUT_FAILED);
193
+ let limiter = limiterWithMockService((succeeds = false));
194
+ let endsInFailure = limiter.transfer("a", "b", -5);
195
+ return expect(endsInFailure).rejects.toThrow(PUT_FAILED);
140
196
  });
141
197
 
142
198
  test("Errors from the underlying service are propagated (take)", () => {
143
- let limiter = limiterWithMockService(succeeds=false);
144
- let endsInFailure = limiter.transfer("a", "b", 5);
145
- return expect(endsInFailure).rejects.toThrow(TAKE_FAILED);
199
+ let limiter = limiterWithMockService((succeeds = false));
200
+ let endsInFailure = limiter.transfer("a", "b", 5);
201
+ return expect(endsInFailure).rejects.toThrow(TAKE_FAILED);
146
202
  });
147
203
 
148
204
  test("Non-conforming response results in an error", () => {
149
- let limiter = limiterWithMockService(succeeds=true, conforms=false);
150
- let endsInFailure = limiter.transfer("a", "b", 5);
151
- return expect(endsInFailure).rejects.toThrow("Non Conformant");
205
+ let limiter = limiterWithMockService((succeeds = true), (conforms = false));
206
+ let endsInFailure = limiter.transfer("a", "b", 5);
207
+ return expect(endsInFailure).rejects.toThrow("Non Conformant");
152
208
  });
153
209
 
154
- test("An operation that fails is not logged", () => {
155
- let limiter = limiterWithMockService();
156
- limiter.transfer("a", "b", -5)
157
- .then(result => {
158
- expect(result).toBe(null)
159
- expect(limiter._limitd._num_tokens()).toBe(5);
160
- limiter.succeeds = false; // somebody is playing games
161
- })
162
- .then(() => limiter.transfer("a", "b", 2))
163
- .catch(() => "failed uniquely!") // do nothing!
164
- .then(result => {
165
- expect(result).toBe("failed uniquely!")
166
- expect(limiter._limitd._num_tokens()).toBe(5);
167
- limiter.succeeds = true; // for real this time
168
- })
169
- .then(() => limiter.revert())
170
- .then(() => {
171
- expect(limiter._limitd._num_tokens()).toBe(0);
172
- done();
173
- })
210
+ test("An operation that fails is not logged", (done) => {
211
+ let limiter = limiterWithMockService();
212
+ limiter
213
+ .transfer("emailRate", "b", -5)
214
+ .then((result) => {
215
+ expect(result).toBe(null);
216
+ expect(limiter._limitdRedis._num_tokens()).toBe(5);
217
+ limiter.succeeds = false; // somebody is playing games
218
+ })
219
+ .then(() => limiter.transfer("emailRate", "b", 2))
220
+ .catch(() => "failed uniquely!") // do nothing!
221
+ .then((result) => {
222
+ expect(result).toBe("failed uniquely!");
223
+ expect(limiter._limitdRedis._num_tokens()).toBe(5);
224
+ limiter.succeeds = true; // for real this time
225
+ })
226
+ .then(() => limiter.revert())
227
+ .then(() => {
228
+ expect(limiter._limitdRedis._num_tokens()).toBe(0);
229
+ done();
230
+ });
174
231
  });
175
232
 
176
- test("Properly handles spamming revert() calls", done => {
177
- let limiter = limiterWithMockService();
178
- limiter.transfer("a", "b", -5)
179
- .then(result => {
180
- expect(result).toBe(null)
181
- expect(limiter._limitd._num_tokens()).toBe(5);
182
- })
183
- .then(() => limiter.transfer("a", "b", 2))
184
- .then(result => {
185
- expect(result).toBe(null)
186
- expect(limiter._limitd._num_tokens()).toBe(3);
187
- })
188
- .then(() =>
189
- Promise.all([
190
- limiter.revert(),
191
- limiter.revert(),
192
- limiter.revert(),
193
- limiter.revert(),
194
- limiter.revert(),
195
- limiter.revert(),
196
- limiter.revert(),
197
- limiter.revert(),
198
- limiter.revert(),
199
- limiter.revert(),
200
- limiter.revert(),
201
- limiter.revert(),
202
- limiter.revert(),
203
- limiter.revert(),
204
- limiter.revert(),
205
- limiter.revert(),
206
- ])
207
- )
208
- .then(() => {
209
- expect(limiter._limitd._num_tokens()).toBe(0);
210
- done();
211
- })
212
- });
233
+ test("Properly handles spamming revert() calls", (done) => {
234
+ let limiter = limiterWithMockService();
235
+ limiter
236
+ .transfer("a", "b", -5)
237
+ .then((result) => {
238
+ expect(result).toMatchObject({});
239
+ expect(limiter._limitdRedis._num_tokens()).toBe(5);
240
+ })
241
+ .then(() => limiter.transfer("a", "b", 2))
242
+ .then((result) => {
243
+ expect(result).toMatchObject({ conformant: true });
244
+ expect(limiter._limitdRedis._num_tokens()).toBe(3);
245
+ })
246
+ .then(() =>
247
+ Promise.all([
248
+ limiter.revert(),
249
+ limiter.revert(),
250
+ limiter.revert(),
251
+ limiter.revert(),
252
+ limiter.revert(),
253
+ limiter.revert(),
254
+ limiter.revert(),
255
+ limiter.revert(),
256
+ limiter.revert(),
257
+ limiter.revert(),
258
+ limiter.revert(),
259
+ limiter.revert(),
260
+ limiter.revert(),
261
+ limiter.revert(),
262
+ limiter.revert(),
263
+ limiter.revert(),
264
+ ])
265
+ )
266
+ .then(() => {
267
+ expect(limiter._limitdRedis._num_tokens()).toBe(0);
268
+ done();
269
+ });
270
+ });
@@ -0,0 +1,31 @@
1
+ var Limiter = require("../limiter");
2
+
3
+ async function performTestWithTestPerMinute() {
4
+ console.log("Testing limitd-redius with bucket testPerMinute");
5
+ const limiter = new Limiter({
6
+ limitdUrl: "localhost:6379",
7
+ console: console,
8
+ });
9
+ // take 2 # Conformant - Remaining: 1
10
+ const result1 = await limiter.transfer("testPerMinute", "key", 2);
11
+ console.log("First Turn Take Result", result1);
12
+
13
+ //Now Conformant - Remaining: 1
14
+ const result2 = await limiter
15
+ .transfer("testPerMinute", "key", 2)
16
+ .catch((err) => {
17
+ console.log("Second Turn Take Error", err.message);
18
+ });
19
+ console.log("Second Turn Take Result", result2);
20
+
21
+ // Put 1
22
+ const result3 = await limiter.transfer("testPerMinute", "key", -1);
23
+ console.log("Third Turn PUT Result", result3);
24
+
25
+ //Now Conformant - Remaining: 2
26
+ const result4 = await limiter.transfer("testPerMinute", "key", 2);
27
+ console.log("Fourth Turn Take Result", result4);
28
+ process.exit(1);
29
+ }
30
+
31
+ performTestWithTestPerMinute();
@@ -1,12 +1,17 @@
1
1
  "use strict";
2
2
 
3
-
4
3
  var Limiter = require("../limiter");
5
4
 
5
+ const buckets = {
6
+ emails: { size: 10 },
7
+ emailRate: { size: 10, per_hour: 10 },
8
+ };
9
+
6
10
  var limiter = new Limiter({
7
- limitdUrl: "limitd://localhost:9231",
8
- console: console
9
- })
11
+ limitdUrl: "localhost:6379",
12
+ console: console,
13
+ buckets,
14
+ });
10
15
 
11
16
  var callback = function (err) {
12
17
  if (err) {
@@ -18,10 +23,10 @@ var callback = function (err) {
18
23
  };
19
24
 
20
25
  var withdrawls = [
26
+ ["emails", process.argv[2], -parseInt(process.argv[3])],
27
+ ["emailRate", process.argv[2], -parseInt(process.argv[3])],
21
28
  ["emails", process.argv[2], parseInt(process.argv[3])],
22
- ["emailRate", process.argv[2], parseInt(process.argv[3])]
29
+ ["emailRate", process.argv[2], parseInt(process.argv[3])],
23
30
  ];
24
31
 
25
- var withdrawlsComplete = [];
26
32
  limiter.transferAll(withdrawls).then(() => callback(), callback);
27
-
@@ -1,14 +0,0 @@
1
- #port to listen on
2
- port: 9231
3
-
4
- #db path
5
- db: ./db
6
-
7
- #define the bucket types
8
- buckets:
9
- emails:
10
- size: 10
11
- emailRate:
12
- size: 10
13
- per_hour: 10
14
-