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

面向Azure的Django站点作业提交与结果自动更新最佳实践咨询

最优方案推荐:Django + Azure VM 创建异步场景实现

Hey Ted, 针对你这个用户提交VM创建作业后无需等待、结果自动更新DOM的需求,我来分享几个比单纯Celery+轮询更高效的实现方案,结合你的场景帮你梳理清楚:

先聊聊你现有方案的痛点

你用的Celery调度+DB存储+前端轮询的方式确实能跑通,但存在几个明显问题:

  • 频繁的轮询请求会浪费服务器和前端资源
  • 结果更新有延迟(取决于轮询间隔)
  • 后端需要主动去Azure查询作业状态,增加了额外的逻辑复杂度

下面是几个更优的方案,按推荐优先级排序:

1. WebSocket 实时推送(最推荐)

这种方式实现真正的实时更新,后端一旦收到Azure的完成通知,立刻推送给前端,完全不需要前端轮询。

实现步骤:

  • 安装django-channels和ASGI服务器(比如Daphne),把Django从WSGI切换到ASGI模式
  • 创建一个WebSocket消费者,用来处理作业状态的推送逻辑:
    # consumers.py
    from channels.generic.websocket import AsyncWebsocketConsumer
    import json
    
    class JobStatusConsumer(AsyncWebsocketConsumer):
        async def connect(self):
            self.job_id = self.scope['url_route']['kwargs']['job_id']
            self.job_group_name = f'job_{self.job_id}'
    
            # 加入作业组
            await self.channel_layer.group_add(
                self.job_group_name,
                self.channel_name
            )
    
            await self.accept()
    
        async def disconnect(self, close_code):
            # 离开作业组
            await self.channel_layer.group_discard(
                self.job_group_name,
                self.channel_name
            )
    
        # 接收作业状态更新
        async def job_status_update(self, event):
            status = event['status']
            result = event['result']
    
            # 发送消息给WebSocket
            await self.send(text_data=json.dumps({
                'status': status,
                'result': result
            }))
    
  • 前端建立WebSocket连接,监听状态更新并更新DOM:
    // 假设作业ID是job123
    const socket = new WebSocket(`ws://your-domain/ws/jobs/job123/`);
    
    socket.onmessage = function(e) {
        const data = JSON.parse(e.data);
        if (data.status === 'completed') {
            // 更新DOM,比如显示VM创建结果
            document.getElementById('job-result').textContent = `VM创建完成:${data.result}`;
        }
    };
    
  • 当Azure返回作业结果时(可以通过Azure的Webhook触发,或者Celery任务查询到结果后),调用Channel Layer推送消息:
    from channels.layers import get_channel_layer
    from asgiref.sync import async_to_sync
    
    def send_job_update(job_id, status, result):
        channel_layer = get_channel_layer()
        async_to_sync(channel_layer.group_send)(
            f'job_{job_id}',
            {
                'type': 'job_status_update',
                'status': status,
                'result': result
            }
        )
    

2. Server-Sent Events (SSE) 单向推送

如果你的场景不需要双向通信(比如用户不需要中途取消作业),SSE是更轻量的选择,不需要额外的WebSocket依赖,实现更简单。

实现步骤:

  • 在Django中写一个SSE视图,保持HTTP连接并推送状态:
    # views.py
    from django.http import StreamingHttpResponse
    import time
    from your_app.models import Job
    
    def job_status_sse(request, job_id):
        def event_stream():
            while True:
                job = Job.objects.get(id=job_id)
                if job.status == 'completed':
                    yield f'data: {job.result}\n\n'
                    break
                # 也可以用Django信号触发,不用轮询DB,更高效
                time.sleep(5)
        return StreamingHttpResponse(event_stream(), content_type='text/event-stream')
    
  • 前端用EventSource监听:
    const source = new EventSource(`/jobs/${job_id}/status/sse/`);
    source.onmessage = function(e) {
        document.getElementById('job-result').textContent = `VM创建完成:${e.data}`;
        source.close(); // 完成后关闭连接
    };
    

3. Azure Event Grid + Django Webhook 深度整合

利用Azure的原生事件系统,当VM创建完成时,Azure主动通知你的Django后端,完全不需要后端主动查询Azure状态。

实现步骤:

  • 在Azure Portal中配置Event Grid订阅,选择"Virtual Machine"作为事件源,订阅Microsoft.Compute/virtualMachines/write事件(VM创建完成的事件)
  • 把订阅的终点设置为你的Django Webhook接口,配置好签名验证(必须做,防止恶意请求)
  • Django的Webhook接口处理Azure的事件,更新作业状态,然后通过上面的WebSocket/SSE推送给前端:
    # views.py
    from django.http import HttpResponse
    from your_app.models import Job
    import json
    
    def azure_event_webhook(request):
        # 验证Azure Event Grid的签名逻辑(参考Azure官方文档实现)
        event_data = json.loads(request.body)
        vm_id = event_data[0]['subject'].split('/')[-1]
        # 根据VM关联到对应的作业
        job = Job.objects.filter(vm_id=vm_id).first()
        if job:
            job.status = 'completed'
            job.result = f'VM {vm_id} 创建成功'
            job.save()
            # 推送状态给前端
            send_job_update(job.id, 'completed', job.result)
        return HttpResponse(status=200)
    

方案选择建议

  • 如果需要实时性最高、支持双向操作(比如用户取消作业),选WebSocket方案
  • 如果只是简单的单向通知,追求实现简单,选SSE方案
  • 如果想深度整合Azure生态,减少后端主动查询逻辑,选Azure Event Grid + WebSocket/SSE

另外,如果你想优化现有Celery方案,可以把固定间隔轮询改成指数退避轮询(比如第一次等10秒,第二次20秒,最多到60秒),减少请求次数,但还是不如推送方案高效。

内容的提问来源于stack exchange,提问作者Ted

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:31:59