From 9df977877e5066478020332bffb0c1677a5cd89e Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Thu, 30 May 2024 13:33:15 +0200 Subject: [PATCH] docs: clarify about atomic operations --- README.md | 6 ++++++ package.json | 5 +++-- test/usage.js | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c94e4a..c6860f8 100644 --- a/README.md +++ b/README.md @@ -365,6 +365,12 @@ Originally this library was implemented using [hashes](https://redis.io/docs/dat Since we need to do that all the time, we prefer to use key/value. Also this approach allow to customize serializer/deserializer, which is JSON by default. +## Are writting operations atomic? + +No, writes operatoins are not atomic because there are very few use cases where that matters. **openkey** is designed to process a constant stream of requests, where the only thing important to control reaching the limit of each plan. + +In case you need it, you can combine **openkey** with [superlock](https://github.com/Kikobeats/superlock), check this example. + # License **openkey** © [microlink.io](https://microlink.io), released under the [MIT](https://github.com/microlinkhq/openkey/blob/master/LICENSE.md) License.
diff --git a/package.json b/package.json index 901d275..67a7e25 100644 --- a/package.json +++ b/package.json @@ -30,10 +30,9 @@ }, "keywords": [], "dependencies": { - "http-body": "~1.0.11", "mri": "~1.2.0", "ms": "~2.1.3", - "send-http": "~1.0.6" + "superlock": "~1.1.3" }, "devDependencies": { "@commitlint/cli": "latest", @@ -55,11 +54,13 @@ "gulp-concat": "latest", "gulp-postcss": "latest", "gulp-uglify": "latest", + "http-body": "latest", "ioredis": "latest", "nano-staged": "latest", "npm-check-updates": "latest", "postcss": "latest", "postcss-focus": "latest", + "send-http": "latest", "simple-git-hooks": "latest", "standard": "latest", "standard-version": "latest" diff --git a/test/usage.js b/test/usage.js index 369124d..7fb0086 100644 --- a/test/usage.js +++ b/test/usage.js @@ -1,6 +1,7 @@ 'use strict' const { setTimeout } = require('timers/promises') +const { withLock } = require('superlock') const { randomUUID } = require('crypto') const Redis = require('ioredis') const test = require('ava') @@ -110,3 +111,28 @@ test(".increment # don't increment more than the limit", async t => { t.is(usage.remaining, 0) } }) + +test('.increment # handle race conditions (using superlock)', async t => { + const lock = withLock() + + const plan = await openkey.plans.create({ + id: randomUUID(), + limit: 1000, + period: '100ms' + }) + const key = await openkey.keys.create({ plan: plan.id }) + + await Promise.all( + [...Array(100).keys()].map(() => + lock(async () => { + const { pending, ...usage } = await openkey.usage.increment(key.value) + await pending + return usage + }) + ) + ) + + const usage = await openkey.usage(key.value) + t.is(usage.limit, 1000) + t.is(usage.remaining, 900) +})