workspace

This commit is contained in:
2026-06-09 17:28:25 +08:00
parent a651e08fff
commit 7eb3647539
6 changed files with 142 additions and 6 deletions
+6 -6
View File
@@ -28,6 +28,7 @@ from app.utils.parse_util import (
get_handle_fee,
get_shipping_fee,
)
from surugaya_common import redis_keys
router = APIRouter(prefix="/api", tags=["scrape"])
@@ -202,7 +203,7 @@ async def order_add_purchase_task(
code=500,
)
stream_name = "jp_surugaya_purchase_task_dev" if payload.is_dev == "1" else "jp_surugaya_purchase_task"
stream_name = redis_keys.purchase_task_stream(payload.is_dev)
params_str = payload.model_dump_json(by_alias=True)
await container.session_store._redis.xadd(
@@ -259,8 +260,7 @@ async def order_add_trade_monitor(
code=400,
)
queue_name = "jp_surugaya_trade_delay_dev" if payload.is_dev == "1" else "jp_surugaya_trade_delay"
queue_name += f":{node_id}"
queue_name = redis_keys.trade_delay_zset(node_id, payload.is_dev)
score = int(time.time()) + 3
member = json.dumps(payload.payload)
@@ -306,18 +306,18 @@ async def trade(
)
trade_data = await container.session_store._redis.hget(
name="jp_surugaya_trade",
name=redis_keys.trade_hash(),
key=trade_code,
)
if not trade_data:
# 去重:同一 trade_code 在 3600s 内不重复下发
dedup_key = f"jp_surugaya_trade_pending:{trade_code}"
dedup_key = redis_keys.trade_pending_key(trade_code)
dedup_exists = await container.session_store._redis.get(dedup_key)
if not dedup_exists:
await container.session_store._redis.setex(dedup_key, 3600, "1")
await container.session_store._redis.xadd(
name="jp_surugaya_trade_fetch",
name=redis_keys.trade_fetch_stream(),
fields={"payload": json.dumps({"trade_code": trade_code})},
maxlen=100,
approximate=True,
+21
View File
@@ -0,0 +1,21 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "surugaya-common"
version = "0.1.0"
description = "Shared contracts (Redis keys, future models) for jp_surugaya services"
requires-python = ">=3.12"
dependencies = [
"pydantic>=2.0.0,<3.0.0",
"redis>=5.0.0,<6.0.0",
]
[tool.hatch.build.targets.wheel]
packages = ["src/surugaya_common"]
# NOTE (deferred): redis pin here intentionally matches the API service (<6).
# The worker's redis==8 requirement is NOT introduced in this increment, so there
# is no conflict to resolve yet. Do not add fastapi/playwright/opencv/numpy/
# pyautogui/pillow here — surugaya_common must stay light.
@@ -0,0 +1,5 @@
"""Shared contracts for jp_surugaya services (Redis keys, future models)."""
from surugaya_common import redis_keys
__all__ = ["redis_keys"]
@@ -0,0 +1,80 @@
"""Centralized Redis key contract shared across jp_surugaya services.
Single source of truth for every Redis key schema. Helper functions reproduce
the EXACT literals currently produced inline by the API service so behaviour is
byte-for-byte identical after refactoring.
Current literals (as of this extraction):
purchase task stream : jp_surugaya_purchase_task[_dev]
trade delay zset : jp_surugaya_trade_delay[_dev]:{node_id}
trade hash : jp_surugaya_trade
trade pending dedup : jp_surugaya_trade_pending:{trade_code}
trade fetch stream : jp_surugaya_trade_fetch
"""
from __future__ import annotations
# --- Base key constants (no suffixes applied) -------------------------------
PURCHASE_TASK_STREAM: str = "jp_surugaya_purchase_task"
TRADE_DELAY_ZSET: str = "jp_surugaya_trade_delay"
TRADE_HASH: str = "jp_surugaya_trade"
TRADE_PENDING_PREFIX: str = "jp_surugaya_trade_pending"
TRADE_FETCH_STREAM: str = "jp_surugaya_trade_fetch"
# Suffix appended to dev-mode keys.
_DEV_SUFFIX: str = "_dev"
def _is_dev(is_dev: object) -> bool:
"""Normalize the dev flag.
The API passes payload.is_dev which is the string "1" for dev mode.
Accepts the raw string flag ("1"), a bool, or anything truthy-comparable
while preserving the exact original semantics (is_dev == "1").
"""
if isinstance(is_dev, str):
return is_dev == "1"
return bool(is_dev)
def purchase_task_stream(is_dev: object = None) -> str:
"""Redis Stream key for the purchase task queue.
Reproduces:
"jp_surugaya_purchase_task_dev" if is_dev == "1" else "jp_surugaya_purchase_task"
"""
if _is_dev(is_dev):
return f"{PURCHASE_TASK_STREAM}{_DEV_SUFFIX}"
return PURCHASE_TASK_STREAM
def trade_delay_zset(node_id: object, is_dev: object = None) -> str:
"""Redis Sorted Set key for delayed trade monitoring, scoped by node_id.
Reproduces:
base = "jp_surugaya_trade_delay_dev" if is_dev == "1" else "jp_surugaya_trade_delay"
base + f":{node_id}"
"""
base = TRADE_DELAY_ZSET
if _is_dev(is_dev):
base = f"{base}{_DEV_SUFFIX}"
return f"{base}:{node_id}"
def trade_hash() -> str:
"""Redis Hash key storing trade order details keyed by trade_code."""
return TRADE_HASH
def trade_pending_key(trade_code: object) -> str:
"""TTL dedup key for a pending trade fetch.
Reproduces: f"jp_surugaya_trade_pending:{trade_code}"
"""
return f"{TRADE_PENDING_PREFIX}:{trade_code}"
def trade_fetch_stream() -> str:
"""Redis Stream key for trade fetch tasks."""
return TRADE_FETCH_STREAM
+7
View File
@@ -14,6 +14,7 @@ dependencies = [
"selectolax>=0.3.21,<1.0.0",
"starlette>=0.37.0,<1.0.0",
"uvicorn[standard]>=0.30.0,<1.0.0",
"surugaya-common",
]
[project.optional-dependencies]
@@ -29,3 +30,9 @@ testpaths = ["tests"]
[tool.uv]
package = false
[tool.uv.workspace]
members = ["packages/*"]
[tool.uv.sources]
surugaya-common = { workspace = true }
Generated
+23
View File
@@ -2,6 +2,12 @@ version = 1
revision = 3
requires-python = ">=3.12"
[manifest]
members = [
"surugaya-common",
"surugaya-scraper-service",
]
[[package]]
name = "annotated-doc"
version = "0.0.4"
@@ -521,6 +527,21 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
]
[[package]]
name = "surugaya-common"
version = "0.1.0"
source = { editable = "packages/surugaya_common" }
dependencies = [
{ name = "pydantic" },
{ name = "redis" },
]
[package.metadata]
requires-dist = [
{ name = "pydantic", specifier = ">=2.0.0,<3.0.0" },
{ name = "redis", specifier = ">=5.0.0,<6.0.0" },
]
[[package]]
name = "surugaya-scraper-service"
version = "0.1.0"
@@ -535,6 +556,7 @@ dependencies = [
{ name = "redis" },
{ name = "selectolax" },
{ name = "starlette" },
{ name = "surugaya-common" },
{ name = "uvicorn", extra = ["standard"] },
]
@@ -557,6 +579,7 @@ requires-dist = [
{ name = "redis", specifier = ">=5.0.0,<6.0.0" },
{ name = "selectolax", specifier = ">=0.3.21,<1.0.0" },
{ name = "starlette", specifier = ">=0.37.0,<1.0.0" },
{ name = "surugaya-common", editable = "packages/surugaya_common" },
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.30.0,<1.0.0" },
]
provides-extras = ["dev"]