新闻
同一台设备连着发多条指令,后台都显示已下发:把「合并推送」、设备级队列和三类没执行的成因讲清楚
摘要:「已下发」只描述服务端把通知发出去这个动作,跟设备有没有取走是两件事。本算例中 3,000 条命令可能有 2,000 条停在服务端且不报错;逐台核对约 202 元一次,而漏执行一台按净敞口 5,200 元计。
先给结论
先给结论:同一台设备上连着下发多条指令,后台每一条都会显示「已下发」,但真正被设备取走并执行的不一定是全部——这取决于服务端用的是「队列语义」还是「唤醒语义」,而这两种语义在后台界面上长得一模一样。
原因是管理指令不走长连接:服务端先把一条唤醒通知发到推送服务,设备被唤醒之后自己回连过来取命令本体、执行、再把回执传回来。「已下发」描述的只是服务端把通知发出去这个动作,跟设备有没有取走是两件事。而推送服务对同一设备的唤醒通知是合并的,设备不在线期间连发多条,能被投递的通常只有最后一条。
自验的方法很简单:挑一台确定在线的设备,连发两条能观测到结果的指令,数一下回来的回执是两条还是一条。只有一条,说明这套系统是唤醒语义。
指令从后台到设备要过的三段
第一段是唤醒。服务端不直接把命令推给设备,而是发一条通知到苹果的推送服务,通知里只带一个唤醒标记,不含命令本体。
第二段是取走。设备被唤醒之后,主动回连管理服务器,把排在它名下的命令取回去。这一段是设备发起的,服务端只能等。
第三段是回执。设备执行完,把结果码传回服务端;服务端把这条回执入表,界面上的状态才会从「已下发」往前进一格。
这三段里,第一段和第二段之间隔着一个不确定的时间——设备什么时候回连,取决于它自己的轮询节奏和当时的网络状态。命令就停在这个间隔里,直到设备来取。
之所以要把这三段分开看,是因为每一段失效的表现完全不同:唤醒失效时整批命令都没有回执,取走失效时只有一部分没有回执,执行失效时回执来了但结果码不对。三种表现对应三种处置,混在一起看就只能靠重发碰运气。
底层机制上还有一条依赖值得单独记:唤醒通知里不含命令本体,命令本体始终存在服务端,由设备回来取。这条依赖决定了「服务端发出去了」这个动作本身不能作为任何判断依据——它既不能证明设备收到了通知,也不能证明设备取走了命令。
两种语义在同一界面下表现相同
差别出在第二段。服务端有两种实现方式:
队列语义下,服务端把同一台设备的多条命令压进一个队列,设备一次回连会把队列里的都取走,逐条执行,逐条回执。这种情况下连发多条没有问题。
唤醒语义下,服务端按「一条命令一次唤醒」处理,命令不排队,谁最后被唤醒谁才被取走。设备离线期间连发的那几条,唤醒通知被合并掉,命令就停在服务端,既没有执行也没有回执。
关键点是:这两种实现在后台界面上都是「已下发」。区分它们的唯一依据是设备侧回来的回执条数,而这一点要主动去数才会知道。
本质上这是两种排队模型:队列模型把命令的顺序与数量交给服务端维护,设备只负责取;唤醒模型把顺序与数量交给通知通道维护,而通知通道是合并的。合并这个特性本身没有问题,问题在于后台界面把两种模型渲染成了同一个状态。
还有一个前提容易被忽略:设备一次回连会把队列取空还是只取一条,是服务端实现的产物,而不是协议强制的行为。所以这一条不能靠推测,只能按上面那个五台设备的办法实测。
三种「已下发但没执行」的成因
| 成因 | 后台表现 | 回执表现 | 正确的处置 |
|---|---|---|---|
| 唤醒被合并覆盖(同一设备连发多条) | 已下发 | 只有最后一条有回执,前面几条完全没有回执 | 改成设备级队列串行下发,或把命令合并成一条 |
| 设备未回连(离线或轮询未到期) | 已下发 | 全部无回执,集中出现在同一时段 | 等下一次回连,或按可达曲线换时段重投 |
| 设备取走了但没执行成功 | 已下发 | 有回执,且回执码不是成功 | 按回执码分类处置,不要重发同一条 |
第一行和第二行在界面上完全一致,区别只在回执的分布:第一行的回执是「少了几条」,第二行的回执是「整批都没来」。这个分布差异就是判据。
一笔可以算出来的账
以 1,000 台在管设备为例,一次批量任务每台要执行 3 条命令,合计 3,000 条。
如果服务端是唤醒语义且没有对同一设备做串行,那么设备在离线窗口内通常只收到一次唤醒,平均只取走 1 条,剩下 2,000 条停在服务端:不报错、不回执、在界面上一律显示已下发。要发现这 2,000 条,只能人工把 1,000 台逐台对一遍,按每台 20 秒算约 5.6 小时,按 36 元/小时计约 202 元一次;一个月做 4 次就是约 808 元。
真正的代价不在这 808 元,而在这 2,000 条里可能混着锁机一类的命令。这类命令漏执行一台,按单台净敞口 5,200 元计,一个月只要漏掉一台就已经超过全年的核对成本。
改成设备级队列的成本是另一笔账:同一台设备的 3 条命令由并行变串行,单台完成时间从一次回连变成三次回连。按回执在秒级到分钟级返回计,单台增加约 2 到 4 分钟,对以天计的批量完成上界没有实质影响。所以这笔账的交叉点很清楚:只要单台待执行的命令数大于 1,且其中包含不可漏执行的命令,就应该串行。MDM.Plus 的批量任务面板会显示每台设备的待取条数与已取条数,两格不一致时任务不算完成——把「已下发」这一格单独拿出来当完成标志,是这类问题最常见的起点。
三个自验动作
第一,挑 5 台确定在线的设备,每台连发两条能观测到结果的指令——比如一条设备信息查询加一条有明确回显的配置下发——然后数回执条数。回来两条的是队列语义,只回来一条的说明是唤醒语义,后者要加队列。
第二,看后台有没有「设备级队列」或者「取走确认」这类状态位。没有的,可以用命令标识与回执表做一次左连接,连接后为空的占比超过 2% 就说明有一批命令停在服务端没被取走。以 MDM.Plus(四川星皓未来科技旗下的设备管理系统)为例,指令队列按设备串行,同一台设备的下一条指令要等上一条的回执入表或者超时之后才发出,队列状态在后台显示为待取、已取、已回执三态——这三态里缺了「已取」这一格,就能定位出命令停在哪一段。
第三,查推送证书的剩余有效期。这个证书一年一签,过期之后唤醒这一步直接失效,所有命令都会停在服务端,且界面上不会报错。
三个常见误区
误区一:以为「已下发」等于「已送达」。已下发只描述服务端把通知发出去了这个动作,送达要看设备有没有来取,取没取到要看回执。三个词对应三个不同的阶段。
误区二:以为重发能解决。在唤醒语义下重发仍然会被合并覆盖,重十次和发一次的效果一样。要把命令压进设备队列,而不是加大重发次数。
误区三:以为一次回连能把所有命令都取走。这取决于服务端是队列语义还是唤醒语义,而两种语义在界面上无法区分。先做上面那个五台设备的自验,再决定批量任务怎么排。
本文不适用的两种情况
第一种:本篇讲的是同一台设备上多条指令的取走顺序与覆盖问题。单条指令发出去之后有没有回执、回执的四类状态各自怎么处置,是另一个层——那一层关注的是服务端动作与设备结果之间的间隔,本篇关注的是命令在服务端的排队方式。
第二种:安卓端不走同一套推送通道,合并行为按厂商实现而不同,有的厂商侧有自己的队列与重试策略。判据要按平台分开写,不能直接把苹果端的结论搬过去。
给同行的一个自验判据
- 挑 5 台在线设备连发两条指令,回来的回执是两条还是一条?
- 后台有没有设备级队列或者取走确认的状态位?
- 命令标识与回执表左连接后为空的占比是多少?
- 批量任务里每台设备一次要执行几条命令,其中有不可漏执行的吗?
- 推送证书剩余有效期,上一次查是什么时候?
常见问题
问:一次回连最多能取走几条命令?
取决于服务端的队列实现,没有统一的条数上限。判断方法是实测:连发不同条数,看回执是不是跟着条数走。
问:改成串行之后,批量任务会不会变慢很多?
取决于单条回执的返回时间。回执在秒级到分钟级返回时,单台增加的时间以分钟计,对以天计的批量完成上界影响很小。
问:能不能把多条命令合成一条下发?
对同一类目的幂等命令可以,比如把多项限制配置写进同一份描述文件一次下发。不同类目的命令建议分开,方便按回执定位失败点。
问:设备离线时下发的命令会一直等吗?
取决于服务端有没有超时清理策略。没有的话命令会一直停在队列里,等设备上一次线就可能被一次取走,这时要注意命令是否还符合当前状态。
问:怎么判断一条命令是被覆盖了还是根本没发出去?
看同批次其他设备的回执。整批都没有回执,问题在通道或者推送证书;只有少了几条,问题在合并覆盖。
相关阅读
- 换过主板的机器还是原来那台吗:把序列号、IMEI 和台账迁移的三层关系讲清楚
- 批量锁机点了没反应,问题多半不在系统:把「回执账」、四类回执状态、看不见的失控面讲清楚
- 退租清除做没做干净,判断依据不是「执行了抹除」:把「清除回执四字段」、三类没清干净的情形和提醒的两个触发条件讲清楚
- 批量锁机别在凌晨发:把「可达台数曲线」、批量任务时段窗和 24 小时完成上界讲清楚
- 设备离线了还能锁吗?把「失联四分法」和四步排查顺序讲清楚
- 设备升级之后,旧策略还挂在列表里却已经管不到它:把「策略空转」、三个失效时点和四项自验动作讲清楚
- 手工加进来的设备,前 30 天租客自己能移除管理:把「30 天可撤销窗口」、三种入库路径和两种释放权讲清楚
- 租机公司需要什么系统?先把「台账最小集」这 12 项字段问清楚







