大家好,这里的bug有点棘手...我们在ClojureScript中使用Safari 7上的core.async时遇到了一些问题。我们的应用程序围绕着一个大型事件循环构建,该循环在一个对应于用户活动或API调用的多个通道之一接收消息时阻塞。问题似乎出在这个事件循环中 - 我们使用alts!从任何可用的通道中拉取消息,但有时日志显示我们到达了alts!却从未解锁。然而,通过更多的日志,我可以看到在alts!通道列表中的一个通道后面有随后的写入操作,所以我真的不知道发生了什么。
这就是总体情况,现在让我们看看代码。
我们的主要事件循环如下
(log "进入主事件循环。")
(go
(while true
(log "alts! 通道散列: " (map hash (:channels @app)))
(let [[message channel] (alts! (seq (:channels @app)))]
(log "alts! 解锁,调用我们的 process-message")
(swap! app process-message message channel)
(log "process-message 完成,循环"))
{{process-message}}是我们在应用程序中的一个内部函数,但我想它的细节并不一定很重要。在Safari卡住的情况下,日志看起来像
[Log] process-message 完成,循环 (main.js, 第62行)
[Log] alts! 通道散列: (16 12 19 33) (main.js, 第82行)
[Log] Socket 已连接。 (socket.js, 第309行)
[Log]向散列为 19 的通道 put! (socket.js, 第86行)
[Log] 消息是 [:metronome [:staff [{:description nil, :deletable true, :email nil, :isAdmin true, :isTrainer false, :telephone nil, :name "Fynder Admin", :picture nil, :userId 1} {:description nil, :deletable fa... (socket.js, 第87行)
[Log] put! 回调返回 us true (socket.js, 第89行)
[Debug] Metronome: staff 数据解码完成。 put! 完成.: 12.282ms (socket.js, 第93行)
[Log]向散列为 19 的通道 put! (socket.js, 第86行)
[Log] 消息是 [:metronome [:class-types [{:deletable false, :picture nil, :name "CycleCore", :id 2, :description "CycleCore 是一种 55 分钟的双项锻炼方案,将 30 分钟的激烈有氧运动与 25 分钟的锻炼强度结合一起... (socket.js, 第87行)
[Log] put! 回调返回 us true (socket.js, 第89行)
[Debug] Metronome: class-types 数据解码完成。 put! 完成.: 1.288ms (socket.js, 第93行)
[Log]向散列为 19 的通道 put! (socket.js, 第86行)
[Log] 消息是 [:metronome [:locations [{:studios [{:deletable false, :name "Kensington", :id 1, :locationId 1, :description "Studio (11a) sits just off Stratford Road in Stratford Studios. To find us, just pass ... (socket.js, 第87行)
[Debug] Metronome: locations 数据解码完成。 put! 完成.: 0.884ms (socket.js, 第93行)
请注意,我们在日志中看到了“alts! channel hashes”的条目,但从未见过“alts! unblocked”。然而,请注意传递给alts!的哈希列表,提到了通道19,但我们随后将其放入通道19,但我们仍然没有被解除阻塞。还有一些事情让我感到可疑,那就是在我们被阻塞在alts!时,对于只能一次包含一个元素的通道,两个put!的调用都立即成功了。也许我理解错了什么,但我不认为立即put回调会被调用多次。有趣的是,最后的put!没有调用回调。
不幸的是,重现这个错误相对困难。我可以通过退出Safari,重新打开它,并导航到开发服务器来有些可靠地重现这个问题。大约15次尝试中会有一次卡在这一状态。我想知道这与Safari的MessageChannel实现有关吗——你可以在日志条目中看到nexttick.js调用回调,这好像是我浏览器中分发的做法。
我将非常乐意提供任何有关信息,但现在我已无法调试这个问题。虽然代码是专有的,但我愿意暂时为GitHub项目添加人员,以尝试修复这个问题。我们有一个开发API服务器,你可以指向它,所以这只需要运行{{lein cljs}}。
我已经附上了我们的Socket.io包装器和主事件循环的代码。遗憾的是,我还没有最小测试用例——我真的不知道该从哪里开始。