レート制限
Omise APIのレート制限内に収まり、効率的な連携を構築します。レート制限ヘッダー、429エラーの適切な処理、リクエストパターンの最適化について学びます。
概要
すべてのマーチャントに信頼性の高いサービスを確保するために、OmiseはAPIリクエストにレート制限を実装しています。レート制限により、単一の連携がAPIを圧倒することを防ぎ、公平なリソース配分を確保します。これらの制限を理解し尊重することは、堅牢な決済連携を構築するために不可欠です。
クイックスタート
- デフォルト制限: APIキーごとに1分あたり1,000リクエスト
- レスポンスの
X-RateLimit-*ヘッダーを監視 - HTTP 429を指数バックオフで処理
- 大量操作にはリクエストキューイングを実装
- 適切な場合はレスポンスをキャッシュ
レート制限の詳細
現在の制限
| 制限タイプ | 値 | スコープ |
|---|---|---|
| 標準レート制限 | 1,000リクエスト/分 | APIキーごと |
| バースト許容 | 約100リクエスト | 短いバーストを許容 |
| リセット期間 | 60秒 | ローリングウィンドウ |
制限にカウントされるもの
✅ カウントされる:
- すべてのAPIリクエスト(GET、POST、PATCH、DELETE)
- 成功したリクエスト(2xxレスポンス)
- 失敗したリクエスト(4xx、5xxレスポンス)
- 認証失敗
❌ カウントされない:
- APIに到達する前にブロックされたリクエスト(無効 なURL)
- 静的アセットリクエスト
- ダッシュボードアクセス
- Omiseからのwebhook配信
レート制限の種類
OmiseはIPベースとアカウントベースの両方のレート制限を実装しており、短時間のバーストには一時的な許容があります。これは、制限がAPIキーごとおよびIPアドレスごとに追跡されることを意味します。
リクエストの優先順位
システムが高負荷の場合、リクエストは以下の順序で優先されます:
| 優先度 | リクエストタイプ | 説明 |
|---|---|---|
| 1(最高) | ライブモードでのPOST/PUT | 課金の作成、キャプチャ、返金 |
| 2 | ライブモードでのGET | トランザクションの一覧表示、課金の取得 |
| 3(最低) | すべてのテストモードリクエスト | テストAPIキーを使用したすべてのリクエスト |
Vaultトークンの制限
Vault(vault.omise.co)でのトークン作成は、メインAPIよりも大幅に低いレート制限があります。連続してトークンを作成することは避け、代わりに有効期間内にトークンを再利用するか、繰り返し使用する場合はカードを顧客にアタッチしてください。
負荷テスト禁止
Omise APIに対する負荷テストは厳禁です。大規模なパフォーマンスを検証する必要がある場合は、適切なテストを手配するためにsupport@omise.coにお問い合わせください。
レート制限ヘッダー
すべてのAPIレスポンスにはレート制限情報がヘッダーに含まれます:
レスポンスヘッダー
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1612137600
ヘッダーの説明
| ヘッダー | 説明 | 例 |
|---|---|---|
X-RateLimit-Limit | ウィンドウ内で許可される最大リクエスト数 | 1000 |
X-RateLimit-Remaining | 現在のウィンドウで残りのリクエスト数 | 995 |
X-RateLimit-Reset | 制限がリセットされるUnixタイムスタンプ | 1612137600 |
コードでヘッダーを読み取る
# Ruby - レート制限ヘッダーを確認
require 'omise'
Omise.api_key = ENV['OMISE_SECRET_KEY']
response = Omise::Charge.retrieve('chrg_test_...')
# ヘッダーにアクセス
limit = response.http_headers['X-RateLimit-Limit']
remaining = response.http_headers['X-RateLimit-Remaining']
reset = response.http_headers['X-RateLimit-Reset']
puts "レート制限: #{remaining}/#{limit}"
puts "リセット時刻: #{Time.at(reset.to_i)}"
// Node.js - レート制限ヘッダーを確認
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
try {
const charge = await omise.charges.retrieve('chrg_test_...');
// レスポンスでヘッダーを利用可能
const headers = charge._response.headers;
const limit = headers['x-ratelimit-limit'];
const remaining = headers['x-ratelimit-remaining'];
const reset = headers['x-ratelimit-reset'];
console.log(`レート制限: ${remaining}/${limit}`);
console.log(`リセット時刻: ${new Date(reset * 1000)}`);
} catch (error) {
console.error('リクエスト失敗:', error);
}
HTTP 429レスポンス
レート制限を超えると、APIはHTTP 429 Too Many Requestsを返します:
429レスポンス形式
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1612137660
Retry-After: 60
{
"object": "error",
"location": "https://www.omise.co/api-errors#rate-limit-exceeded",
"code": "rate_limit_exceeded",
"message": "too many requests, please try again later"
}
レスポンスフィールド
| フィールド | 説明 |
|---|---|
code | "rate_limit_exceeded" |
message | 人間可読のエラーメッセージ |
Retry-After | 再試行まで待機する秒数 |
レート制限の処理
戦略1: 指数バックオフ(推奨)
増加する遅延でリトライ:
# Ruby - 指数バックオフ
require 'omise'
def create_charge_with_backoff(params, max_attempts: 5)
attempt = 0
begin
attempt += 1
Omise::Charge.create(params)
rescue Omise::Error => e
if e.code == 'rate_limit_exceeded' && attempt < max_attempts
# バックオフ遅延を計算: 1秒、2秒、4秒、8秒、16秒
delay = 2 ** (attempt - 1)
# サンダリングハード防止のためジッター(ランダム性)を追加
jitter = rand(0..delay * 0.1)
sleep(delay + jitter)
retry
else
raise
end
end
end
# 使用方法
charge = create_charge_with_backoff(
amount: 100000,
currency: 'thb',
card: token
)
// Node.js - 指数バックオフ
async function createChargeWithBackoff(chargeData, maxAttempts = 5) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await omise.charges.create(chargeData);
} catch (error) {
if (error.code !== 'rate_limit_exceeded' || attempt === maxAttempts - 1) {
throw error;
}
// ジッター付き遅延を計算
const baseDelay = Math.pow(2, attempt) * 1000;
const jitter = Math.random() * baseDelay * 0.1;
const delay = baseDelay + jitter;
console.log(`レート制限。${(delay / 1000).toFixed(2)}秒後にリトライ...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// 使用方法
const charge = await createChargeWithBackoff({
amount: 100000,
currency: 'thb',
card: token
});
戦略2: Retry-Afterヘッダーを尊重
サーバーが提案するリトライ時間を使用:
<?php
function createChargeWithRetryAfter($params, $maxAttempts = 5) {
$attempt = 0;
while ($attempt < $maxAttempts) {
try {
$attempt++;
return OmiseCharge::create($params);
} catch (Exception $e) {
if ($e->getCode() !== 'rate_limit_exceeded' || $attempt >= $maxAttempts) {
throw $e;
}
// レスポンスからRetry-Afterヘッダーを取得
$retryAfter = $e->getResponse()->getHeader('Retry-After');
$delay = $retryAfter ? (int)$retryAfter : 60;
echo "レート制限。{$delay}秒待機中...\n";
sleep($delay);
}
}
throw new Exception('最大リトライ回数を超過');
}
// 使用方法
$charge = createChargeWithRetryAfter([
'amount' => 100000,
'currency' => 'thb',
'card' => $token
]);
最適化戦略
1. レスポンスをキャッシュ
# Ruby - Redisでキャッシュ
require 'redis'
class OmiseCache
def initialize
@redis = Redis.new
end
def get_charge(charge_id)
cache_key = "charge:#{charge_id}"
# まずキャッシュを試行
cached = @redis.get(cache_key)
return JSON.parse(cached) if cached
# APIから取得
charge = Omise::Charge.retrieve(charge_id)
# 5分間キャッシュ
@redis.setex(cache_key, 300, charge.to_json)
charge
end
end
cache = OmiseCache.new
# 最初の呼び出し - APIにヒット
charge = cache.get_charge('chrg_test_...')
# 以降の呼び出し - キャッシュから(APIリクエストなし)
charge = cache.get_charge('chrg_test_...')
2. ポーリングの代わりにWebhookを使用
// ❌ 悪い例 - ポーリングはレート制限を浪費
async function waitForChargeComplete(chargeId) {
let charge;
// 2秒ごとにポーリング - リクエストを浪費!
while (true) {
charge = await omise.charges.retrieve(chargeId);
if (charge.status === 'successful' || charge.status === 'failed') {
return charge;
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
// ✅ 良い例 - Webhookを使用
app.post('/webhooks/omise', async (req, res) => {
const event = req.body;
if (event.key === 'charge.complete') {
const charge = event.data;
// 完了 した課金を処理
await processCharge(charge);
}
res.sendStatus(200);
});