fix(map): rate limit station reverse geocoding

This commit is contained in:
lingniu
2026-08-12 12:04:39 +08:00
parent 4c547757a7
commit 5b565d57fc
3 changed files with 13 additions and 1 deletions
+2
View File
@@ -10,3 +10,5 @@ AMAP_REGEOCODE_KEY=replace-with-amap-web-service-key
# 行政区结果按坐标落盘缓存 7 天,避免每次刷新重复调用高德。
STATION_GEOCODE_CACHE_SECONDS=604800
STATION_GEOCODE_CACHE_PATH=/opt/lingniu-vehicle-map/cache/station-geocode.json
# 高德 Web 服务常见 QPS 配额较低;全局限速以避免冷缓存时触发 10021。
AMAP_REGEOCODE_MIN_INTERVAL_SECONDS=0.25
+1 -1
View File
@@ -32,7 +32,7 @@ python3 server.py
- `POST /api/v1/vehicles/mileage/query`:全部授权车辆当日里程;
- `POST /api/v1/hydrogen-stations/query`:资产库只读加氢站地图点位。
以上三个接口均使用开放平台的 `Authorization: Bearer <AppKey>` 鉴权。生产 AppKey 仅保存在 ECS 的 `/opt/lingniu-vehicle-map/env/vehicle-map.env`,文件权限为 `root:vehicle-map 0640`。同一配置文件中的 `AMAP_REGEOCODE_KEY` 仅在服务端使用:站点省、市、区按 GCJ-02 坐标调用高德逆地理生成,不能使用资产表的行政区字段;结果以坐标为键落盘缓存 7 天。详细地址仍直接保留资产原始字段。
以上三个接口均使用开放平台的 `Authorization: Bearer <AppKey>` 鉴权。生产 AppKey 仅保存在 ECS 的 `/opt/lingniu-vehicle-map/env/vehicle-map.env`,文件权限为 `root:vehicle-map 0640`。同一配置文件中的 `AMAP_REGEOCODE_KEY` 仅在服务端使用:站点省、市、区按 GCJ-02 坐标调用高德逆地理生成,不能使用资产表的行政区字段;请求通过全局速率限制避免高德 QPS 限流,结果以坐标为键落盘缓存 7 天。详细地址仍直接保留资产原始字段。
本服务提供:
+10
View File
@@ -38,12 +38,15 @@ STATION_GEOCODE_CACHE_SECONDS = int(os.getenv("STATION_GEOCODE_CACHE_SECONDS", "
STATION_GEOCODE_CACHE_PATH = Path(os.getenv(
"STATION_GEOCODE_CACHE_PATH", str(ROOT / ".station-geocode-cache.json")
))
AMAP_REGEOCODE_MIN_INTERVAL_SECONDS = float(os.getenv("AMAP_REGEOCODE_MIN_INTERVAL_SECONDS", "0.25"))
_cache_lock = threading.Lock()
_cache = {}
_cache_load_locks = {}
_station_geocode_cache_lock = threading.Lock()
_station_geocode_cache = None
_station_geocode_cache_dirty = False
_station_geocode_rate_lock = threading.Lock()
_station_geocode_next_request_at = 0.0
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
@@ -142,8 +145,15 @@ def _persist_station_geocode_cache():
def _reverse_geocode_station(longitude, latitude):
global _station_geocode_next_request_at
if not AMAP_REGEOCODE_KEY:
raise RuntimeError("AMAP_REGEOCODE_KEY is not configured")
with _station_geocode_rate_lock:
now = time.monotonic()
wait_seconds = max(0.0, _station_geocode_next_request_at - now)
_station_geocode_next_request_at = max(now, _station_geocode_next_request_at) + AMAP_REGEOCODE_MIN_INTERVAL_SECONDS
if wait_seconds:
time.sleep(wait_seconds)
query = urlencode({
"key": AMAP_REGEOCODE_KEY,
"location": "{:.6f},{:.6f}".format(longitude, latitude),