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

如何让Delayed Job自动入队?Rails中Azure媒体服务视频更新任务

嘿,我刚好做过类似的Rails+Azure媒体服务集成,针对你用Delayed Job处理视频状态持续更新的需求,给你几个实用的方案,从易实现到最优解都有:

方案1:任务自调度(最适配Delayed Job的常规玩法)

核心思路就是让任务自己检查视频状态,如果还在处理中,就重新调度自己,直到拿到最终的可用/失败状态。给你补全下你的Job代码:

class UpdateAzureVideosJob < ApplicationJob
  queue_as :azure_media_service

  def perform
    # 只捞处于处理中的视频,别瞎折腾已完成的
    pending_videos = AzureVideo.where(status: :processing)

    pending_videos.each do |video|
      # 调用Azure API拿当前处理状态
      azure_status = fetch_azure_video_status(video.azure_asset_id)

      case azure_status
      when "Available"
        video.update!(status: :available, processed_url: get_azure_processed_url(video))
      when "Failed"
        video.update!(status: :failed, error_message: get_azure_error_details(video))
      else
        # 还在处理?10分钟后再跑一次这个任务(间隔根据你的平均处理时长调)
        self.class.set(wait: 10.minutes).perform_later
        # 批量处理的话,只调度一次就够,别每个视频都发任务
        break
      end
    end
  end

  private

  def fetch_azure_video_status(asset_id)
    # 这里写调用Azure媒体服务API的逻辑,不管是用官方gem还是自己写HTTP请求都行
  end

  def get_azure_processed_url(video)
    # 从Azure拿处理后的视频流地址
  end

  def get_azure_error_details(video)
    # 拿失败原因
  end
end

为啥这个好用?

  • 完全贴合Delayed Job的工作逻辑,不用额外搞进程管理
  • 可以灵活调整轮询间隔,避免频繁怼Azure API被限流
  • 批量处理待更新视频,减少任务数量,效率更高
方案2:单视频独立任务+重试机制

如果你的视频处理时长差异很大,不想批量处理拖慢进度,可以给每个视频单独开任务,利用Delayed Job的重试特性:

class UpdateAzureVideoJob < ApplicationJob
  queue_as :azure_media_service
  # 最多重试24次(每10分钟一次就是4小时,够大部分视频处理完了)
  retry_on VideoProcessingInProgressError, attempts: 24, wait: 10.minutes

  def perform(video_id)
    video = AzureVideo.find(video_id)
    # 已经完成的直接溜,别做无用功
    return if video.status.in?([:available, :failed])

    azure_status = fetch_azure_video_status(video.azure_asset_id)

    case azure_status
    when "Available"
      video.update!(status: :available, processed_url: get_azure_processed_url(video))
    when "Failed"
      video.update!(status: :failed, error_message: get_azure_error_details(video))
    else
      # 抛个自定义异常触发重试
      raise VideoProcessingInProgressError, "Video #{video_id} still being processed"
    end
  end

  class VideoProcessingInProgressError < StandardError; end
end

适用场景:

  • 每个视频的处理时长差异大,批量处理可能导致快完成的视频被慢的拖后腿
  • 想精细化控制单个视频的重试次数和间隔
方案3:Azure Webhook(最优解,彻底告别轮询)

其实Azure媒体服务支持状态变更Webhook,视频处理完(成功/失败)时,Azure会主动发请求到你的Rails接口,完全不用你主动轮询,效率拉满。

实现步骤:

  1. 先在Azure媒体服务后台配置Webhook,指向你的Rails接口(比如POST /azure_webhooks/video_status)
  2. 在Rails里写个控制器处理这个Webhook请求:
class AzureWebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token 
  # 划重点:一定要验证Azure的请求签名!别啥请求都接,防止被伪造

  def video_status
    payload = JSON.parse(request.body.read)
    asset_id = payload["assetId"]
    status = payload["status"]

    video = AzureVideo.find_by(azure_asset_id: asset_id)
    if video
      case status
      when "Completed"
        video.update!(status: :available, processed_url: payload["outputUrl"])
      when "Failed"
        video.update!(status: :failed, error_message: payload["errorDetails"])
      end
    end

    head :ok
  end
end
  1. 之后你只需要在视频上传到Azure后,跑一次初始状态检查任务,剩下的就等Azure主动通知就行。

为啥这是最优解?

  • 完全不用轮询,省资源还没延迟
  • 状态变了立刻响应,用户体验更好
  • 减少Delayed Job的任务量,降低系统负载
生产环境必注意的坑
  • 队列监控:整个delayed_job_web这类工具盯着队列,别让任务丢了都不知道
  • 错误处理:不管用啥方案,都要处理Azure API调用失败的情况(比如网络波动),别让任务无限重试
  • 幂等性:确保任务重复执行不会搞乱数据(比如别把已标记为可用的视频再更一遍)
  • 队列隔离:把Azure相关的任务放到单独的azure_media_service队列,别和其他业务任务抢资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:32:09