c514a75026
期权链拉取遇限频时退避重试并回退短缓存,前端提示更友好。 Co-authored-by: Cursor <cursoragent@cursor.com>
56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
"""期权合约列表缓存与限频退避."""
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from lib.exchange import okx_options_lib as m
|
|
|
|
|
|
class FetchOptionInstrumentsCacheTests(unittest.TestCase):
|
|
def setUp(self):
|
|
m.invalidate_option_instruments_cache()
|
|
|
|
def tearDown(self):
|
|
m.invalidate_option_instruments_cache()
|
|
|
|
def test_cache_hit_skips_second_api_call(self):
|
|
ex = MagicMock()
|
|
ex.public_get_public_instruments.return_value = {
|
|
"data": [
|
|
{
|
|
"instId": "ETH-USD_UM-260812-2000-C",
|
|
"state": "live",
|
|
"expTime": "9999999999999",
|
|
}
|
|
]
|
|
}
|
|
a = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
|
b = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
|
self.assertEqual(len(a), 1)
|
|
self.assertEqual(len(b), 1)
|
|
self.assertEqual(ex.public_get_public_instruments.call_count, 1)
|
|
|
|
@patch("lib.exchange.okx_options_lib.time.sleep", return_value=None)
|
|
def test_rate_limit_falls_back_to_stale_cache(self, _sleep):
|
|
ex = MagicMock()
|
|
ex.public_get_public_instruments.return_value = {
|
|
"data": [{"instId": "ETH-USD_UM-260812-2000-C", "state": "live"}]
|
|
}
|
|
first = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
|
self.assertEqual(len(first), 1)
|
|
# 过期 TTL,但仍在 stale 窗口
|
|
with m._INSTRUMENTS_CACHE_LOCK:
|
|
m._INSTRUMENTS_CACHE["ETH-USD_UM"]["updated_at"] = time.time() - 120
|
|
ex.public_get_public_instruments.side_effect = Exception(
|
|
'okx {"msg":"Too Many Requests","code":"50011"}'
|
|
)
|
|
second = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
|
self.assertEqual(len(second), 1)
|
|
self.assertEqual(second[0]["instId"], "ETH-USD_UM-260812-2000-C")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|