You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中实现请求队列,管控物理储物柜授权流程?

基于DRF的实体储物柜授权队列与超时处理方案

需求场景

  • 用户验证授权全部成功:储物柜pin码替换为通用提示+开柜门(已有实现)
  • 授权3分钟超时:自动替换pin码为通用提示
  • 授权进行中收到新请求:存入队列,前序请求处理完成后再执行

核心问题解决方案

1. 请求队列实现(避免pin码被覆盖)

每个储物柜对应独立的FIFO队列,同时配置处理中状态标记:

  • 新请求进入时先判断储物柜状态,未在处理中则直接执行当前请求,生成对应pin码展示,标记状态为处理中
  • 如果当前正在处理中,直接把新请求的用户信息、jwt凭证等参数推入对应储物柜的队列即可
  • 队列可直接用Redis缓存的list结构实现,不想搭额外服务也可以用Django ORM建AuthorizationQueue表,字段存储:储物柜ID、用户信息、jwt_token、请求时间、请求状态

2. 3分钟授权超时实现

用异步延时任务实现超时自动处理,推荐用Celery:

  • 每次取出队列请求开始处理时,提交一个延时3分钟执行的超时处理任务,把任务ID存入缓存/队列表
  • 用户3分钟内完成授权:先取消对应延时任务,执行原有开柜、展示通用提示的逻辑,再将储物柜状态设为未处理,检查队列是否有待处理请求,有则取出下一个执行
  • 3分钟内未完成授权:延时任务自动触发,执行展示通用提示逻辑,设置储物柜状态为未处理,同样检查队列执行下一个请求

补充说明:不想引入Celery依赖的话,也可以用Django Q或者定时任务轮询AuthorizationQueue表中处理中超过3分钟的请求,批量执行超时逻辑,仅实时性稍差。


参考实现代码

from django.core.cache import cache
from your_app.celery import app
from celery.result import AsyncResult

# 授权超时时间 单位秒
AUTH_TIMEOUT = 180

def authorization_view(request, jwt_token):
    # 从jwt解析出对应储物柜ID,逻辑自行实现
    bay_id = get_bay_id_from_jwt(jwt_token)
    processing_key = f"bay:{bay_id}:processing"
    queue_key = f"bay:{bay_id}:queue"
    timeout_task_key = f"bay:{bay_id}:timeout_task_id"

    if request.method == 'POST':
        form = ConfirmationForm(request.POST)
        if form.is_valid():
            current_pin = cache.get(f"bay:{bay_id}:current_pin")
            if current_pin == form.cleaned_data['pin']:
                # 授权成功,先取消超时任务
                timeout_task_id = cache.get(timeout_task_key)
                if timeout_task_id:
                    AsyncResult(timeout_task_id).revoke(terminate=True)
                # 原有业务逻辑
                open_bay(jwt_token=jwt_token, pin=current_pin)
                display_generic_message(jwt_token=jwt_token)
                lock_bay(jwt_token=jwt_token, pin=current_pin)
                # 清理当前请求相关缓存
                cache.delete_many([processing_key, timeout_task_key, f"bay:{bay_id}:current_pin"])
                # 处理队列下一个请求
                process_next_queue(bay_id)
                return render(request, 'static/pages/request-success.html')
    else:
        # 新授权请求进入
        if cache.get(processing_key):
            # 推入队列,返回等待提示页
            cache.rpush(queue_key, jwt_token)
            return render(request, 'static/pages/waiting.html', {"msg": "请等待前序用户完成操作"})
        # 未在处理中,直接执行当前请求
        generate_and_display_pin(bay_id)
        cache.set(processing_key, True, AUTH_TIMEOUT + 10)
        # 提交超时任务
        timeout_task = handle_timeout.apply_async((bay_id,), countdown=AUTH_TIMEOUT)
        cache.set(timeout_task_key, timeout_task.id, AUTH_TIMEOUT + 10)
        form = ConfirmationForm()
    return render(request, 'static/pages/confirmation.html', {'form': form})

# 超时处理异步任务
@app.task
def handle_timeout(bay_id):
    display_generic_message(jwt_token=get_current_jwt(bay_id))
    cache.delete_many([f"bay:{bay_id}:processing", f"bay:{bay_id}:timeout_task_key", f"bay:{bay_id}:current_pin"])
    # 处理队列下一个请求
    process_next_queue(bay_id)

# 取出队列下一个请求执行
def process_next_queue(bay_id):
    queue_key = f"bay:{bay_id}:queue"
    if cache.llen(queue_key) > 0:
        next_jwt = cache.lpop(queue_key)
        next_bay_id = get_bay_id_from_jwt(next_jwt)
        generate_and_display_pin(next_bay_id)
        cache.set(f"bay:{next_bay_id}:processing", True, AUTH_TIMEOUT + 10)
        timeout_task = handle_timeout.apply_async((next_bay_id,), countdown=AUTH_TIMEOUT)
        cache.set(f"bay:{next_bay_id}:timeout_task_id", timeout_task.id, AUTH_TIMEOUT + 10)

内容的提问来源于stack exchange,提问作者S Person D Person

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 04:39:01