好的,这可能不算是严格意义上的“bug”,也许是设计如此,但我对 JS 端如何更新在线状态有些疑问。文件是 app/assets/javascripts/discourse/app/services/presence.js
到目前为止,我的理解是 JS 客户端:
当更新队列不为空时,会将更新频率限制为每秒一次
然后在没有更改时每 30 秒发送一次请求
我注意到的是,如果服务器因任何原因出错,JS 将继续每秒发送请求。同时会在控制台产生错误 Uncaught (in promise),第 565 行。
它不应该在 N 次错误后停止,以免使服务器过载吗?
如何复现?
在 presence_controller.rb 的 update 方法中模拟一个错误。(在我的例子中,我只是为了演示而渲染了状态 405)
def update
# JS 客户端设计为每秒节流一次
# 当没有进行更改时,它每 30 秒发送一次请求
RateLimiter.new(nil, "update-presence-#{current_user.id}", 20, 10.seconds).performed!
render json: { error: "Not authorized" }, status: 405
return
...
然后在客户端进入任何带有在线状态管理的屏幕。我选择了主题回复屏幕并开始回复。
结果是它会永远每秒钟持续发送请求。
1 个赞
Mubramaj:
然后每 30 秒请求一次,当没有更改时
另外,每 30 秒重新计算一次用户在线状态真的有必要吗?因为有:
执行 enter 操作时进行一次计算
执行 leave 操作时进行一次计算
用户在线状态更改时进行一次计算
sam
(Sam Saffron)
2023 年6 月 13 日 06:24
4
这里的需求是出错时“退避”,这样的话,在重复出错时,我们会退避到大约 30 秒……
1 个赞
david
(David Taylor)
2023 年6 月 13 日 08:42
5
1 个赞
@david 抱歉造成误解。
我最初的主题帖子与此无关:FIX: use `_presentChannels.size` instead of `_presentChannels.length`… · discourse/discourse@589add7 · GitHub
即使没有每 30 秒的计划更新,如果后端出现任何错误,算法也会每秒重试,因为事件队列将不为空:
在 _scheduleNextUpdate 中
} else if (this._queuedEvents.length > 0) {
this._cancelTimer();
cancel(this._debounceTimer);
this._debounceTimer = debounce(
this,
this._throttledUpdateServer,
this._presenceDebounceMs // 我认为这是 1 秒
);
事实上,在 _updateServer 方法中 → 事件会在出错时放回队列:
} catch (e) {
// 将失败的事件放回队列以供下次使用
this._queuedEvents.unshift(...queue);
这只是我后来注意到的……当一切顺利(意味着没有错误)时,真的有必要每 30 秒更新一次服务器吗?
} else if (
!this._nextUpdateTimer &&
this._presentChannels.size > 0 &&
!isTesting()
) {
this._nextUpdateTimer = discourseLater(
this,
this._throttledUpdateServer,
PRESENCE_INTERVAL_S * 1000 // 这是 30 秒
);
}
1 个赞
我不认为有退避机制。当出现任何错误时,它会每秒重试一次,而且不会停止。但也许我错过了什么。
1 个赞
好的,我想我明白了为什么它需要每 30 秒“签到”一次。
有一个后台作业每分钟触发一次 PresenceChannelAutoLeave,它将使过期的成员离开频道。
它也在 presence_channel.rb 中为 present(user:, client_id:) 方法进行了注释:
# Mark a user's client as present in this channel. The client_id should be unique per
# browser tab. This method should be called repeatedly (at least once every DEFAULT_TIMEOUT)
# while the user is present in the channel.
def present(user:, client_id:)
仍然想知道每秒触发的错误部分。
david
(David Taylor)
2023 年7 月 28 日 21:36
10
我们已经正确处理了 429 “速率限制”错误。但对于其他意外错误,我添加了一些指数退避逻辑(上限为 30 秒)。感谢您引起我们的注意 @AhmedLoud
main ← presence-error-backoff
opened 09:35PM - 28 Jul 23 UTC
We already handled 429 rate limit errors correctly. This commit adds backoff log… ic to other types of error to avoid requests being retried every second.
https://meta.discourse.org/t/268063
3 个赞