mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 17:08:03 +08:00
Merge branch 'fix/api-token-lock' of github.com:langgenius/dify into fix/api-token-lock
This commit is contained in:
@ -328,10 +328,10 @@ def validate_and_get_api_token(scope: str | None = None):
|
||||
# Cache miss - use Redis lock for single-flight mode
|
||||
# This ensures only one request queries DB for the same token concurrently
|
||||
logger.debug("Token cache miss, attempting to acquire query lock for scope: %s", scope)
|
||||
|
||||
|
||||
lock_key = f"api_token_query_lock:{scope}:{auth_token}"
|
||||
lock = redis_client.lock(lock_key, timeout=10, blocking_timeout=5)
|
||||
|
||||
|
||||
try:
|
||||
if lock.acquire(blocking=True):
|
||||
try:
|
||||
@ -341,12 +341,12 @@ def validate_and_get_api_token(scope: str | None = None):
|
||||
if cached_token is not None:
|
||||
logger.debug("Token cached by concurrent request, using cached version")
|
||||
return cached_token
|
||||
|
||||
|
||||
# Still not cached - query database
|
||||
with Session(db.engine, expire_on_commit=False) as session:
|
||||
current_time = naive_utc_now()
|
||||
update_token_last_used_at(auth_token, scope, current_time, session=session)
|
||||
|
||||
|
||||
stmt = select(ApiToken).where(ApiToken.token == auth_token, ApiToken.type == scope)
|
||||
api_token = session.scalar(stmt)
|
||||
|
||||
@ -364,7 +364,7 @@ def validate_and_get_api_token(scope: str | None = None):
|
||||
with Session(db.engine, expire_on_commit=False) as session:
|
||||
current_time = naive_utc_now()
|
||||
update_token_last_used_at(auth_token, scope, current_time, session=session)
|
||||
|
||||
|
||||
stmt = select(ApiToken).where(ApiToken.token == auth_token, ApiToken.type == scope)
|
||||
api_token = session.scalar(stmt)
|
||||
|
||||
@ -380,7 +380,7 @@ def validate_and_get_api_token(scope: str | None = None):
|
||||
with Session(db.engine, expire_on_commit=False) as session:
|
||||
current_time = naive_utc_now()
|
||||
update_token_last_used_at(auth_token, scope, current_time, session=session)
|
||||
|
||||
|
||||
stmt = select(ApiToken).where(ApiToken.token == auth_token, ApiToken.type == scope)
|
||||
api_token = session.scalar(stmt)
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ class CachedApiToken(BaseModel):
|
||||
|
||||
This is NOT a SQLAlchemy model instance, but a plain Pydantic model
|
||||
that mimics the ApiToken model interface for read-only access.
|
||||
|
||||
|
||||
Using Pydantic provides:
|
||||
- Automatic type validation
|
||||
- Better IDE support
|
||||
@ -82,7 +82,7 @@ class ApiTokenCache:
|
||||
# If it's already a Pydantic model, use model_dump_json
|
||||
if isinstance(api_token, CachedApiToken):
|
||||
return api_token.model_dump_json()
|
||||
|
||||
|
||||
# Otherwise, convert from SQLAlchemy model
|
||||
data = {
|
||||
"id": str(api_token.id),
|
||||
|
||||
Reference in New Issue
Block a user