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

R simmer资源容量归0时未丢弃到达实体的问题排查与修正

问题描述

仿真场景中,部分资源采用随时段交替切换0/1容量的调度策略:

  • 若资源在容量降至0前无法完成任务,到达实体需被丢弃,短暂等待后回滚至「选择可用资源」环节;
  • 若无可用资源,则进入「超时→回滚」循环直至有资源可用。

原实现代码如下:

# Use a reject trajectory used to go back and select a new resource if the
# current resource runs out of time (i.e., its shift ends)
... |> 
simmer::seize_selected(
  continue = TRUE,
  reject = simmer::trajectory('dropped') |>
    simmer::timeout(() runif(1, min = 0.07, max = 0.1)) |>
    simmer::rollback(target = 'select_resource')
  ) |>

# Clear the queue of the selected resource when its capacity is zero
simmer::renege_if(
  signal = 'clear_queue'
  ) |>
simmer::send(
  signals =  () {
    cap <- simmer::get_capacity_selected(env)

    res_name <- simmer::get_selected(env)
    now <- simmer::now(env)

    queue_count <- simmer::get_queue_count_selected(env)
    if (res_name == 'Operator_Bill' & now > 41 & queue_count > 0) {
      browser()
    }

    if (cap == 0) {
      'clear_queue'
      } else {
        ''
      }
    }
  ) |> ...

当前问题:

  • 调试条件从未触发;
  • 查看mon_resources发现,资源容量为0时仍有实体处于服务或排队状态。

问题分析
  1. 信号监听与发送顺序错误:原代码中send在renege_if之后执行,实体还未注册clear_queue信号监听就收到了信号,导致信号无法被捕获。
  2. 信号触发时机单一:send仅在实体进入流程时执行一次,无法响应后续资源容量的动态变化,资源容量切换时无法通知已排队/服务的实体。
  3. 抢占逻辑不符合需求:seize_selected(continue = TRUE)会让抢占失败的实体继续执行后续流程,违背「丢弃后回滚」的设计。
  4. 调试逻辑触发条件不足:实体在资源容量变为0前已进入服务/排队,且信号未正确触发,导致queue_count的判断逻辑从未满足。

修正后的代码

1. 资源容量调度与全局信号触发

在资源容量切换时主动发送信号,替代实体流程中的单次检查:

# 示例:定时切换Operator_Bill的容量,切换时触发信号
env |> 
  simmer::schedule_capacity(
    resource = "Operator_Bill",
    schedule = data.frame(
      start_time = c(0, 40),
      end_time = c(40, Inf),
      capacity = c(1, 0)
    ),
    # 容量切换时的回调动作
    action = function(env, resource) {
      current_cap <- simmer::get_capacity(env, resource)
      now <- simmer::now(env)
      queue_count <- simmer::get_queue_count(env, resource)
      
      # 调试逻辑:资源容量为0、时间超41且有排队实体时触发
      if (resource == "Operator_Bill" && now > 41 && queue_count > 0 && current_cap == 0) {
        browser()
      }
      
      # 容量变为0时发送清队列信号
      if (current_cap == 0) {
        simmer::send_signal(env, "clear_queue")
      }
    }
  )

2. 实体流程轨迹修正

调整抢占、信号监听的顺序与逻辑,确保流程符合设计要求:

simmer::trajectory("entity_flow") |>
  # 标记选择资源的节点,用于回滚
  simmer::mark("select_resource") |>
  # 选择可用资源(需提前定义select逻辑)
  simmer::select(...) |>
  # 抢占选中资源:抢占失败直接进入回滚流程
  simmer::seize_selected(
    continue = FALSE,  # 抢占失败不执行后续服务逻辑
    reject = simmer::trajectory("dropped") |>
      simmer::timeout(() runif(1, 0.07, 0.1)) |>
      simmer::rollback(target = "select_resource")
  ) |>
  # 注册监听clear_queue信号,触发后释放资源并回滚
  simmer::renege_if(
    signal = "clear_queue",
    out = simmer::trajectory("queue_cleared") |>
      simmer::release_selected() |>  # 释放已抢占的资源,避免占用
      simmer::timeout(() runif(1, 0.07, 0.1)) |>
      simmer::rollback(target = "select_resource")
  ) |>
  # 执行任务流程
  simmer::timeout(() rnorm(1, mean = 5)) |>
  simmer::release_selected()

关键说明
  • 信号触发时机优化:通过schedule_capacity的action回调,在资源容量切换时主动发送信号,确保所有监听的实体能及时响应。
  • 抢占逻辑修正:continue = FALSE让抢占失败的实体直接进入回滚流程,避免无效的后续执行。
  • 回滚流程完整性:renege_if的out轨迹中添加release_selected(),防止实体占用已切换为0容量的资源。
  • 调试逻辑调整:将调试检查移到容量切换的回调中,确保满足条件时触发调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:52:33