コンテンツにスキップ
UniKVS
Esc
↑↓移動↵開く⌘Jプレビュー
このページの内容

@unikvs/rate-limit

トークンバケットで操作頻度を制限するミドルウェアです。

概要

RateLimit はトークンバケットで操作頻度を制限し、過剰な読み書きからストレージを保護します。Middleware

バーストを許容しつつ平均速度を抑えたいときに使います。制限超過時は待機か即時エラーを選べます。

  • name は RateLimit です。
  • isOpen は常に true です。
  • バケットはキーごとではなくミドルウェアインスタンスで共有され、すべての操作 (set・get・stream・has・delete・copy・move・clear) で 1 トークンを消費します。
  • encode・decode・encodeStream・decodeStream はデータを透過します。

インストールは次のコマンドで行います。

npm install @unikvs/rate-limit
pnpm add @unikvs/rate-limit
yarn add @unikvs/rate-limit
bun add @unikvs/rate-limit
nub add @unikvs/rate-limit
aube add @unikvs/rate-limit

使い方

RateLimit は IMiddleware を実装しています。UniKvs には use() で渡します。

import { RateLimit } from "@unikvs/rate-limit";

コンストラクターの引数は次のとおりです。

プロパティ型
tokensPerInterval?number

1 インターバルあたりに補充されるトークン数です。

型number
デフォルト1
intervalMs?number

トークンを補充する間隔 (ミリ秒) です。

型number
デフォルト1000
maxTokens?number

保持できるトークンの上限です。既定値は max(1, tokensPerInterval) です。1 未満を明示すると構築に失敗します。

型number
burst?number

maxTokens の別名です。両方を指定した場合は maxTokens が優先されます。1 未満を明示すると構築に失敗します。

型number
strategy?RateLimitStrategy

レート制限を超えたときの挙動です。"wait" は補充まで待機し、"throw" は直ちにエラーを投げます。

型RateLimitStrategy
デフォルト"wait"
now?() => number

現在時刻 (epoch ミリ秒) を返す関数です。既定値は Date.now です。

型() => number
デフォルトDate.now
sleep?IRateLimitSleep

待機処理です。既定では setTimeout を使います。テストで時刻を制御するときに差し替えることができます。

型IRateLimitSleep

以下は、1 秒あたり 5 操作までに制限し、超過時は待機する例です。

import { Memory } from "@unikvs/memory";
import { RateLimit } from "@unikvs/rate-limit";
import * as unikvs from "unikvs";

const kvs = new unikvs.Builder<{ k1: unikvs.PlainValue<string> }>()
  .use(new RateLimit({ tokensPerInterval: 5, intervalMs: 1000 }))
  .persist(new Memory())
  .build();

await kvs.open();
await kvs.set("k1", "hello");
console.log(await kvs.get("k1")); // "hello"
await kvs.close();

RateLimit

トークンバケットで操作頻度を制限するミドルウェアです。このミドルウェアは PassThrough を継承し、データ変換は行いません。

RateLimitOptions

RateLimit のコンストラクターが受け取るオプションです。トークン数と補充間隔、超過時の挙動を指定できます。

RateLimitStrategy

レート制限を超えたときの挙動です。"wait" ではトークンが補充されるまで待機し、"throw" では直ちにエラーを投げます。

IRateLimitSleep

待機処理の実装です。テストで時刻を制御するときに差し替えることができます。

データ型

メソッド 入力 出力
encode any any
decode any any
encodeStream any any
decodeStream any any
  • use は操作ごとに 1 トークンを消費し、データ内容には触れません。
  • encode・decode・encodeStream・decodeStream は入力をそのまま通し、変換を行いません。
  • トークンは経過時間に応じて補充され、上限を超えて増えることはありません。時計が戻ってもトークンは増えません。
  • maxTokens を省略した場合の容量は max(1, tokensPerInterval) です。1 回の操作で 1 トークン消費するため、tokensPerInterval が 1 未満でも容量は 1 になります。
  • maxTokens または burst に 1 未満を明示すると、構築時に RateLimitInvalidOptionError を投げます。tokensPerInterval には 1 未満の小数を指定できます。
  • wait 戦略では回復まで待機し、要求は先着順に実行されます。このミドルウェアは中断シグナルでは待機を打ち切ります。

エラー

このパッケージが投げるエラーは次のとおりです。

RateLimitExceededError

プロパティ型
retryAfterMsnumber

再試行までに待つべき時間 (ミリ秒) です。

型number

意味

strategy が "throw" のときにトークンが不足したまま操作が呼ばれると、このエラーが投げられます。next は呼ばれず、操作は実行されません。

対処方法

meta.retryAfterMs の時間だけ待って再試行するか、strategy を "wait" にして自動待機を使ってください。頻発する場合は tokensPerInterval や maxTokens を見直してください。

例

以下は、RateLimitExceededError を捕捉する例です。

import { RateLimitExceededError } from "@unikvs/rate-limit";

try {
  await kvs.set("k1", "hello");
} catch (ex) {
  if (ex instanceof RateLimitExceededError) {
    console.log(ex.meta); // { retryAfterMs: 500 }
  } else {
    throw ex;
  }
}

RateLimitInvalidOptionError

プロパティ型
namestring

不正だったオプション名です。

型string
actualunknown

指定された値です。

型unknown

意味

コンストラクターに不正なオプションが渡されると、このエラーが投げられます。正で有限の数値ではない値、1 未満の maxTokens と burst、"wait"・"throw" 以外の strategy、関数でない now・sleep が対象です。

対処方法

meta.name のオプションを確認し、正の有限数や正しい列挙値、関数を指定してください。maxTokens と burst の両指定では maxTokens が優先されます。

例

以下は、RateLimitInvalidOptionError を捕捉する例です。

import { RateLimit, RateLimitInvalidOptionError } from "@unikvs/rate-limit";

try {
  const limiter = new RateLimit({ intervalMs: 0 });
} catch (ex) {
  if (ex instanceof RateLimitInvalidOptionError) {
    console.log(ex.meta); // { name: "intervalMs", actual: 0 }
  } else {
    throw ex;
  }
}

中断シグナルによる AbortError はそのまま伝播し、このミドルウェアはトークンを消費しません。

このページは役に立ちましたか?