Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make NewMessageCounter async #2464

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Make NewMessageCounter async #2464

wants to merge 6 commits into from

Conversation

nagaeki
Copy link

@nagaeki nagaeki commented Jun 24, 2024

Fixes #2157

Copy link
Contributor

@pikachu0310 pikachu0310 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビュー遅くてごめんなさい!
貢献ありがとうございます!かなりいい感じなのですが、初期化を待つ処理が無いので、初期化中にGETされてしまうと返す値がズレてしまいそうです。惜しいです!

こうすればできそう~という、僕が思いついた簡易的な実装を書いたので、参考にして修正してみて下さい~!

Comment on lines 17 to 20
var (
messagesCounter prometheus.Counter
once sync.Once
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

以下の様にチャネルも定義して、初期化の完了を他のゴルーチンに通知する事で上手く実装出来そうです。

Suggested change
var (
messagesCounter prometheus.Counter
once sync.Once
)
var (
messagesCounter prometheus.Counter
initOnce sync.Once
initDone = make(chan struct{})
)

Comment on lines 55 to 56
go func() {
for range hub.Subscribe(1, event.MessageCreated).Receiver {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

初期化チェックを追加

Suggested change
go func() {
for range hub.Subscribe(1, event.MessageCreated).Receiver {
go func() {
<-initDone
for range hub.Subscribe(1, event.MessageCreated).Receiver {

以下の様に、Get() の所にも追加するべき。

func (c *messageCounterImpl) Get() int64 {
	<-initDone
	c.RLock()
	defer c.RUnlock()
	return c.count
}

Comment on lines 50 to 52
})
messagesCounter.Add(float64(counter.count))
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

初期化が完了したことを通知する

Suggested change
})
messagesCounter.Add(float64(counter.count))
})
})
messagesCounter.Add(float64(counter.count))
close(initDone)
})

panic(err)
}

once.Do(func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(少し変数名を変えたので、変更)

Suggested change
once.Do(func() {
initOnce.Do(func() {


go func() {
if err := db.Unscoped().Model(&model.Message{}).Count(&counter.count).Error; err != nil {
panic(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

panic ではなく、エラーを返すようにしたいな~
initError みたいな変数を用意して格納させるとかで良さそう。

@pikachu0310
Copy link
Contributor

pikachu0310 commented Jul 23, 2024

機能面は良さそうです!ありがとうございます!

ただ、@motoki317https://q.trap.jp/messages/e55d6ed9-ad4e-42bc-bce8-f65844b3f34d を参考にすると、かなりコードを簡素にかつ分かりやすくできると気づいたため、リファクタリングをしました。

具体的には、

  • sync.RWMutex から sync/atomic にすることで、軽量でより読みやすくしました。
  • 初期化とカウンターの増加部分を関数で分離しました。
  • Get() と inc() の最初に sync.Once を呼び出すことで、初期化が保証されるようにして、sync.Once の特徴を上手く活かす形にしました。
  • count をグローバル変数にして、不要な変数を削除しました。

Comment on lines +46 to +51
initOnce.Do(func() {
initError = mc.initializeCounter()
})
if initError != nil {
return nil, initError
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

結局これでは非同期にはなりません...

sync.Onceは、Doを呼んだらそれが返ったときには、ただ一度だけ中の関数の実行が終了しているという性質を持ちます。
↓を参考にしたり、もしよかったらsync.Onceの実装の中身も覗いてみてください。
https://q.trap.jp/messages/50247bdf-5920-4bfa-8a12-c4d789b74792
https://cs.opensource.google/go/go/+/refs/tags/go1.22.5:src/sync/once.go;l=18
(sync.OnceFuncもだいたい同じで、こちらの方が今回の場合は使いやすいかも)

この性質と、promauto.CounterFuncで値をこちら側でコントロールできる性質を活かして、立ち上がり時はブロックしないけど、値を取得するときには初期化が終了していることを表現してみてください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

立ち上がり時にメッセージ数をCOUNTしていて遅い
3 participants