-
Notifications
You must be signed in to change notification settings - Fork 191
Fix the links to the examples project in the Chinese version of the README; add a close callback mechanism for sessions. #91
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
Conversation
WalkthroughAdds an internal singly-linked callback registry and per-session, thread-safe close-callback subsystem; integrates asynchronous callback invocation with panic recovery into session shutdown; adds unit tests and updates README/README_CN with callback documentation and example links. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor App as Application
participant Sess as session
participant Reg as callbacks
participant CB1 as callback#1
participant CB2 as callback#2
Note over App,Sess: Registration
App->>Sess: AddCloseCallback(h1,k1,f1)
Sess->>Reg: Add(h1,k1,f1)
App->>Sess: AddCloseCallback(h2,k2,f2)
Sess->>Reg: Add(h2,k2,f2)
rect rgb(230,245,255)
Note over App,Sess: Shutdown (async)
App->>Sess: stop()
Sess->>Sess: spawn goroutine -> invokeCloseCallbacks()
Sess->>Reg: Invoke()
Reg->>CB1: call f1()
Reg->>CB2: call f2()
Sess->>Sess: recover panics, log
end
sequenceDiagram
autonumber
actor App as Application
participant Sess as session
participant Reg as callbacks
App->>Sess: RemoveCloseCallback(handler,key)
alt session open
Sess->>Reg: Remove(handler,key)
Reg-->>Sess: list updated
else session closed
Sess-->>App: no-op
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
README_CN.md (2)
21-21
: Wrap the URL in Markdown to satisfy MD034 and keep punctuation outside the link.
This avoids the “bare URL” lint warning and reads cleaner in rendered Markdown.-有关代码示例,请参阅 https://github.com/AlexStocks/getty-examples +有关代码示例,请参阅 [AlexStocks/getty-examples](https://github.com/AlexStocks/getty-examples)。
21-21
: Convert bare URLs to Markdown links
Replace bare URLs with properly formatted links and ensure trailing punctuation is outside the link:
- README_CN.md:21: change
有关代码示例,请参阅 https://github.com/AlexStocks/getty-examples
to
有关代码示例,请参阅 [getty-examples](https://github.com/AlexStocks/getty-examples)
- README.md:21: change
For code examples, you can refer to https://github.com/AlexStocks/getty-examples.
to
For code examples, you can refer to [getty-examples](https://github.com/AlexStocks/getty-examples).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
README_CN.md
(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
README_CN.md
21-21: Bare URL used
(MD034, no-bare-urls)
🔇 Additional comments (1)
README_CN.md (1)
21-21
: Fix makes the examples link clickable — good catch.
Removing the trailing Chinese period avoids breaking the GitHub autolink.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (13)
transport/callback.go (5)
6-10
: Use any instead of interface{} for consistencyThe codebase elsewhere uses any; align field types here.
Apply this diff:
type callbackCommon struct { - handler interface{} // 处理器标识,用于标识回调的来源或类型 - key interface{} // 回调的唯一标识键,与 handler 组合使用 + handler any // 处理器标识,用于标识回调的来源或类型 + key any // 回调的唯一标识键,与 handler 组合使用 call func() // 实际要执行的回调函数 next *callbackCommon // 指向下一个节点的指针,形成链表结构 }
24-42
: Guard against incomparable identifiers to avoid runtime panics on equalityhandler/key that are not comparable (e.g., slices, maps) can cause a panic during Remove comparisons. Either document the constraint or proactively reject such additions.
Apply this diff and import reflect:
+import "reflect" @@ -func (t *callbacks) Add(handler, key interface{}, callback func()) { +func (t *callbacks) Add(handler, key any, callback func()) { // 防止添加空回调函数 if callback == nil { return } + + // handler/key 必须可比较,否则后续移除时可能触发运行时 panic + if (handler != nil && !reflect.TypeOf(handler).Comparable()) || + (key != nil && !reflect.TypeOf(key).Comparable()) { + return + }And update Remove signature similarly (see next comment).
49-73
: Keep Remove signature consistent with AddUpdate parameter types to any to match Add and the rest of the codebase.
Apply this diff:
-func (t *callbacks) Remove(handler, key interface{}) { +func (t *callbacks) Remove(handler, key any) {
79-86
: Harden Invoke: snapshot + per-callback panic isolationA single callback panic aborts the rest. Also, holding locks during Invoke (if added externally) can deadlock if callbacks call Remove. Execute a snapshot and isolate panics.
Apply this diff:
-func (t *callbacks) Invoke() { - // 从头节点开始遍历整个链表 - for callback := t.first; callback != nil; callback = callback.next { - // 确保回调函数不为 nil 再执行 - if callback.call != nil { - callback.call() - } - } -} +func (t *callbacks) Invoke() { + // 构建快照,避免遍历期间结构被修改 + var fns []func() + for cb := t.first; cb != nil; cb = cb.next { + if cb.call != nil { + fns = append(fns, cb.call) + } + } + // 逐个执行,隔离 panic,保证后续回调仍可执行 + for _, fn := range fns { + func(f func()) { + defer func() { _ = recover() }() + f() + }(fn) + } +}
1-17
: Unify comment languageRepo comments are mostly English; consider translating these headers for consistency.
transport/session.go (1)
879-888
: Include stack trace when a close-callback panicsMatch existing panic logging style elsewhere in this file for easier debugging.
Apply this diff:
- go func() { - defer func() { - if r := recover(); r != nil { - log.Errorf("invokeCloseCallbacks panic: %v", r) - } - }() - // 执行关闭回调函数 - s.invokeCloseCallbacks() - }() + go func() { + defer func() { + if r := recover(); r != nil { + const size = 64 << 10 + buf := make([]byte, size) + n := runtime.Stack(buf, false) + log.Errorf("invokeCloseCallbacks panic: %v\n%s", r, string(buf[:n])) + } + }() + // 执行关闭回调函数 + s.invokeCloseCallbacks() + }()transport/callback_test.go (1)
1-100
: Minor: unify test messages languageConsider English messages for consistency with the rest of the repo.
transport/session_callback_test.go (4)
19-26
: Make the test deterministic; replace sleeps/mutex with a done channel.Sleeping to “wait” for callbacks is flaky and slow. A buffered channel makes the assertion race-free and reliable.
- var callbackExecuted bool - var callbackMutex sync.Mutex - - callback := func() { - callbackMutex.Lock() - callbackExecuted = true - callbackMutex.Unlock() - } + doneCh := make(chan struct{}, 1) + callback := func() { doneCh <- struct{}{} } @@ - // 等待回调执行 - time.Sleep(50 * time.Millisecond) - - callbackMutex.Lock() - if !callbackExecuted { - t.Error("回调函数未被执行") - } - callbackMutex.Unlock() + // 等待回调执行(带超时) + select { + case <-doneCh: + case <-time.After(200 * time.Millisecond): + t.Error("回调函数未在预期时间内执行") + }Also applies to: 49-57
67-79
: Eliminate flakiness in multi-callback test; count via channel instead of sleeps.Use a buffered channel to collect completions instead of shared counters and sleeps.
- var callbackCount int - var callbackMutex sync.Mutex + doneCh := make(chan struct{}, totalCallbacks) @@ - callback := func() { - callbackMutex.Lock() - callbackCount++ - callbackMutex.Unlock() - } + callback := func() { doneCh <- struct{}{} } @@ - time.Sleep(50 * time.Millisecond) - - callbackMutex.Lock() - if callbackCount != expectedAfterRemove { - t.Errorf("期望执行的回调数量为 %d,实际为 %d", expectedAfterRemove, callbackCount) - } - callbackMutex.Unlock() + // 等待剩余回调全部完成(带超时) + timeout := time.After(300 * time.Millisecond) + for i := 0; i < expectedAfterRemove; i++ { + select { + case <-doneCh: + case <-timeout: + t.Fatalf("仅收到 %d/%d 个回调完成信号", i, expectedAfterRemove) + } + }Also applies to: 99-105
120-130
: Avoid shadowing the callbacks type name; rename the local slice for clarity.The local variable named “callbacks” shadows the type callbacks and hurts readability.
- // 添加多个不同类型的关闭回调 - callbacks := []struct { + // 添加多个不同类型的关闭回调 + cases := []struct { handler string key string action string }{ @@ - // 注册所有回调 - for _, cb := range callbacks { + // 注册所有回调 + for _, cb := range cases { cbCopy := cb // 捕获循环变量 callback := func() { callbackMutex.Lock() callbackResults = append(callbackResults, cbCopy.action) callbackMutex.Unlock() } s.AddCloseCallback(cbCopy.handler, cbCopy.key, callback) }Also update the length check below:
- expectedCount := len(callbacks) + expectedCount := len(cases)Also applies to: 132-141
148-159
: Remove arbitrary sleep; assert synchronously or use a wait primitive.After calling Invoke(), rely on immediate execution or a wait primitive (e.g., WaitGroup/channel) instead of time.Sleep(10ms). This reduces test flakiness.
transport/session_callback.go (2)
3-14
: Clarify key constraints in docs.If the underlying registry keys on handler/key directly, require them to be comparable (or stringify them internally) to avoid runtime panics.
61-69
: Naming nit: prefer CallbackFunc.Minor consistency nit with common Go naming (“Callback” vs “CallBack”).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
transport/callback.go
(1 hunks)transport/callback_test.go
(1 hunks)transport/session.go
(3 hunks)transport/session_callback.go
(1 hunks)transport/session_callback_test.go
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
transport/session.go (2)
transport/session_callback.go (1)
CallBackFunc
(68-68)util/logger.go (1)
Errorf
(171-173)
transport/session_callback.go (4)
transport/client_test.go (1)
newSessionCallback
(83-95)transport/getty.go (1)
OnOpen
(68-94)examples/echo/udp-echo/server/app/handler.go (1)
h
(139-144)examples/echo/tcp-echo/server/app/handler.go (1)
h
(129-134)
🔇 Additional comments (3)
transport/callback.go (1)
12-17
: Document and enforce thread-safety expectationscallbacks is not concurrency-safe; please document that all access must be serialized by an external mutex (as you do with session.closeCallbackMutex), or make the type self-synchronized. Right now, concurrent Add/Remove/Invoke without external locking would race.
transport/session.go (1)
879-888
: Confirm ordering relative to OnCloseinvokeCloseCallbacks runs in a new goroutine; OnClose is invoked immediately after stop returns in handlePackage’s defer. If ordering matters for users, please document or make invocation synchronous.
transport/callback_test.go (1)
7-48
: Tests cover happy-path add/remove/invoke semantics—LGTMGood coverage of Count, nil callback ignore, removal by (handler,key), and execution order via accumulation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
transport/callback_test.go (4)
8-12
: Add a no-op Invoke on empty registry to catch panics early.
Covers the empty-path behavior explicitly.if cb.Count() != 0 { t.Errorf("Expected count for empty list is 0, but got %d", cb.Count()) } + + // Ensure invoking on an empty registry is a no-op (no panic). + cb.Invoke()
33-37
: Also assert replacement semantics for duplicate (handler,key).
Ensure Add replaces (not duplicates) when a non-nil fn is added for the same pair.cb.Add(remove, remove, nil) if cb.Count() != expectedCallbacks { t.Errorf("Expected count after adding nil callback is %d, but got %d", expectedCallbacks, cb.Count()) } + + // Replace an existing callback with a non-nil one; count should remain unchanged. + cb.Add(remove, remove, func() { count += remove }) + if cb.Count() != expectedCallbacks { + t.Errorf("Expected count after replacing existing callback is %d, but got %d", expectedCallbacks, cb.Count()) + }
49-52
: Rename var for clarity.
This value is a sum, not a count.- expectedCount := expected - remove - if count != expectedCount { - t.Errorf("Expected execution result is %d, but got %d", expectedCount, count) + expectedSum := expected - remove + if count != expectedSum { + t.Errorf("Expected execution result is %d, but got %d", expectedSum, count)
92-92
: Add a panic-safety test for Invoke.
If Invoke is intended to be panic-safe, assert it.} + +func TestCallbackInvokePanicSafe(t *testing.T) { + cb := &callbacks{} + var ran bool + cb.Add("h", "k1", func() { panic("boom") }) + cb.Add("h", "k2", func() { ran = true }) + // Expect: Invoke swallows panics and continues executing remaining callbacks. + cb.Invoke() + if !ran { + t.Errorf("Expected subsequent callbacks to run even if one panics") + } +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
transport/callback_test.go
(1 hunks)transport/session.go
(3 hunks)transport/session_callback.go
(1 hunks)transport/session_callback_test.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- transport/session.go
- transport/session_callback_test.go
- transport/session_callback.go
🔇 Additional comments (3)
transport/callback_test.go (3)
20-25
: Good capture of loop variable.
Using an IIFE with ii avoids the classic closure-over-loop-var bug in Go.
54-82
: Nice coverage of head/middle/tail removals.
Validates list integrity across common edge cases.
1-1
: All transport files consistently usepackage getty
. No inconsistencies detected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
transport/session.go (1)
105-106
: API surface expanded—verify all implementers and document contract
- Breaking change: all Session implementers must define these methods.
- Please also document the callback semantics (when invoked relative to OnClose, single vs multiple invocation, thread-safety, idempotency, and whether callbacks may block).
Apply optional inline docs:
- AddCloseCallback(handler, key any, callback CallBackFunc) - RemoveCloseCallback(handler, key any) + // Register a function to run when the session closes. Should be fast/non-blocking and idempotent. + AddCloseCallback(handler, key any, callback CallBackFunc) + // Remove a previously registered close callback identified by (handler, key). + RemoveCloseCallback(handler, key any)
🧹 Nitpick comments (2)
transport/session.go (2)
141-145
: Callbacks state needs explicit init/Reset intent—confirm zero-value invariants
- Storing
closeCallback
by value assumes its zero value is a valid empty registry. Confirm this is true.Reset()
reassigns*s = session{...}
, implicitly zeroing bothcloseCallback
andcloseCallbackMutex
. If that’s intended (drop all callbacks), please make it explicit or add a comment; if not, reinitialize/retain appropriately. EnsureReset()
is never called concurrently.Optionally make the intent explicit in Reset:
func (s *session) Reset() { - *s = session{ + *s = session{ name: defaultSessionName, once: &sync.Once{}, done: make(chan struct{}), period: period, wait: pendingDuration, attrs: gxcontext.NewValuesContext(context.Background()), + // callbacks: intentionally cleared on reset + // closeCallback: zero-value (empty registry) + // closeCallbackMutex: zero-value (unlocked) } }
872-880
: Safer panic logging for callback goroutine; clarify ordering vs OnClose
- Capture a stack trace to aid debugging if callbacks panic.
- Please also confirm whether callbacks are intended to run before, after, or concurrently with
listener.OnClose(s)
; today they run concurrently. If ordering matters, enforce or document it.Apply this small logging improvement:
- go func() { - defer func() { - if r := recover(); r != nil { - log.Errorf("invokeCloseCallbacks panic: %v", r) - } - }() - s.invokeCloseCallbacks() - }() + go func() { + defer func() { + if r := recover(); r != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + log.Errorf("invokeCloseCallbacks panic: %v\n%s", r, buf) + } + }() + s.invokeCloseCallbacks() + }()Optional: if an endpoint task pool exists, consider dispatching via
EndPoint().GetTaskPool().AddTaskAlways(...)
instead of a bare goroutine.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
transport/session.go
(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
transport/session.go (2)
transport/session_callback.go (1)
CallBackFunc
(68-68)util/logger.go (1)
Errorf
(171-173)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (3)
transport/session_callback.go (3)
31-38
: Fix TOCTOU and nil-callback; lock first, re-check closed, ignore nil.Race between IsClosed and Lock; nil f would panic downstream.
func (s *session) AddCloseCallback(handler, key any, f CallBackFunc) { - if s.IsClosed() { - return - } - s.closeCallbackMutex.Lock() - s.closeCallback.Add(handler, key, f) - s.closeCallbackMutex.Unlock() + if f == nil { + return + } + s.closeCallbackMutex.Lock() + defer s.closeCallbackMutex.Unlock() + if s.IsClosed() { + return + } + s.closeCallback.Add(handler, key, f) }
52-59
: Apply same TOCTOU fix to RemoveCloseCallback.Check closed under the lock to avoid races.
func (s *session) RemoveCloseCallback(handler, key any) { - if s.IsClosed() { - return - } - s.closeCallbackMutex.Lock() - s.closeCallback.Remove(handler, key) - s.closeCallbackMutex.Unlock() + s.closeCallbackMutex.Lock() + defer s.closeCallbackMutex.Unlock() + if s.IsClosed() { + return + } + s.closeCallback.Remove(handler, key) }
61-76
: Don’t hold locks while invoking callbacks; add panic recovery.Invoking under RLock can deadlock if callbacks call Add/Remove; comment promises recover but none exists.
func (s *session) invokeCloseCallbacks() { - s.closeCallbackMutex.RLock() - s.closeCallback.Invoke() - s.closeCallbackMutex.RUnlock() + // run without holding locks to avoid re-entrancy deadlocks + defer func() { + if r := recover(); r != nil { + // TODO: log recover with stack + } + }() + s.closeCallback.Invoke() }
🧹 Nitpick comments (5)
transport/session_callback_test.go (5)
60-74
: Deflake: wait on a signal instead of sleeping.Sleep-based waiting is brittle and slow; signal when callback runs.
- go func() { - time.Sleep(10 * time.Millisecond) - s.stop() - }() - - // Wait for callback execution - time.Sleep(50 * time.Millisecond) + doneCh := make(chan struct{}, 1) + // augment callback to signal completion + orig := callback + callback = func() { + orig() + doneCh <- struct{}{} + } + // re-register with signal-capable callback + s.RemoveCloseCallback("testHandler", "testKey") + s.AddCloseCallback("testHandler", "testKey", callback) + + go s.stop() + select { + case <-doneCh: + case <-time.After(200 * time.Millisecond): + t.Fatal("timeout waiting for callback") + }
110-123
: Deflake multi-callback assertion; count signals instead of sleeping.Use a buffered channel to await exact number of executions.
- // Test execution of remaining callbacks when closing - go func() { - time.Sleep(10 * time.Millisecond) - s.stop() - }() - - time.Sleep(50 * time.Millisecond) + // Test execution of remaining callbacks when closing + doneCh := make(chan struct{}, totalCallbacks) + // re-register callbacks to signal execution + s.closeCallback = callbacks{} + for i := 1; i < totalCallbacks; i++ { // skip 0 as removed + idx := i + s.AddCloseCallback(fmt.Sprintf("handler%d", idx), fmt.Sprintf("key%d", idx), func() { + callbackMutex.Lock() + callbackCount++ + callbackMutex.Unlock() + doneCh <- struct{}{} + }) + } + go s.stop() + for i := 0; i < expectedAfterRemove; i++ { + select { + case <-doneCh: + case <-time.After(200 * time.Millisecond): + t.Fatalf("timeout waiting for callback %d", i) + } + }
170-176
: Exercise the production path: call invokeCloseCallbacks() directly; drop sleeps.This ensures recover/lock semantics are actually tested.
- // Execute all close callbacks - s.closeCallback.Invoke() - - // Wait for callback execution to complete - time.Sleep(10 * time.Millisecond) + // Execute all close callbacks via session + s.invokeCloseCallbacks() @@ - // Execute callbacks again - s.closeCallback.Invoke() - time.Sleep(10 * time.Millisecond) + // Execute callbacks again + s.invokeCloseCallbacks()Also applies to: 198-201
225-234
: Consistency: prefer session.invokeCloseCallbacks in edge-case checks.Keeps tests aligned with real invocation behavior.
- // Execute empty callback list (should not panic) - s.closeCallback.Invoke() + // Execute empty callback list (should not panic) + s.invokeCloseCallbacks() @@ - // Execute empty list after removal (should not panic) - s.closeCallback.Invoke() + // Execute empty list after removal (should not panic) + s.invokeCloseCallbacks()
27-35
: Add tests for nil callbacks, add-after-close, and panic recovery.Covers important edge cases implied by the API and comments.
I can add subtests:
- AddCloseCallback(nil) is ignored.
- AddCloseCallback after s.stop() is ignored.
- A callback that panics does not crash tests (recover verified).
Want me to push a patch?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
README.md
(1 hunks)README_CN.md
(1 hunks)transport/callback.go
(1 hunks)transport/callback_test.go
(1 hunks)transport/session.go
(4 hunks)transport/session_callback.go
(1 hunks)transport/session_callback_test.go
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- README.md
🚧 Files skipped from review as they are similar to previous changes (4)
- transport/callback_test.go
- transport/callback.go
- README_CN.md
- transport/session.go
🧰 Additional context used
🧬 Code graph analysis (1)
transport/session_callback.go (4)
transport/client_test.go (1)
newSessionCallback
(83-95)transport/getty.go (1)
OnOpen
(68-94)examples/echo/tcp-echo/client/app/client.go (1)
c
(62-75)examples/echo/tcp-echo/server/app/handler.go (1)
h
(129-134)
todo: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (3)
README_CN.md (1)
34-47
: Add a short runtime guidance note.建议在示例下补一句“关闭回调应尽量快速、避免阻塞或长耗时操作,否则可能延长会话关闭耗时;重活移交到独立 goroutine”。
transport/callback.go (1)
118-129
: Optional: track size for O(1) Len.若 Len 调用较频繁,可在结构体中维护 size 计数,在 Add/Remove 中增减,避免每次 O(n) 遍历。当前实现功能正确,此项为优化建议。
README.md (1)
34-47
: State runtime expectations for callbacks.Add a one-liner: “Callbacks should be fast/non-blocking; move heavy work to separate goroutines to avoid delaying shutdown.”
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
README.md
(1 hunks)README_CN.md
(1 hunks)transport/callback.go
(1 hunks)transport/callback_test.go
(1 hunks)transport/session.go
(4 hunks)transport/session_callback_test.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- transport/session_callback_test.go
- transport/session.go
🧰 Additional context used
🧬 Code graph analysis (2)
transport/callback.go (3)
transport/client_test.go (1)
newSessionCallback
(83-95)transport/client.go (1)
c
(422-427)transport/getty.go (2)
ID
(97-110)OnOpen
(68-94)
README_CN.md (1)
transport/getty.go (1)
OnOpen
(68-94)
🔇 Additional comments (7)
README_CN.md (1)
21-22
: Link fix LGTM.Markdown link to getty-examples is correct and clearer.
transport/callback.go (3)
1-16
: License header LGTM.Header conforms to ASF Apache-2.0.
18-20
: Go version verified — no action required. go.mod specifies "go 1.25", which satisfies the >= 1.18 requirement for using any.
104-116
: Recover per-callback to match getty’s panic-safety convention.Wrap each callback invocation with defer/recover, log the stack trace, and continue executing subsequent callbacks; update tests accordingly.
File: transport/callback.go (lines 104-116)
func (t *callbacks) Invoke() { // Traverse the entire linked list starting from the head node for callback := t.first; callback != nil; callback = callback.next { // Ensure callback function is not nil before executing if callback.call != nil { - callback.call() + func() { + defer func() { + if r := recover(); r != nil { + const size = 64 << 10 + buf := make([]byte, size) + n := runtime.Stack(buf, false) + log.Printf("panic in callback: %v\n%s", r, string(buf[:n])) + } + }() + callback.call() + }() } } }No matches for 'dubbogo/gost/log' were found in the repo scan — confirm the repository’s logging convention and replace log.Printf with the project logger/import if one exists.
README.md (1)
21-22
: Link fix LGTM.Clearer Markdown link to getty-examples.
transport/callback_test.go (2)
24-79
: Solid coverage for Add/Len/Remove/Invoke happy paths.Covers empty list, nil callback ignored, replacement semantics, and final sum.
80-118
: Good edge-case removals.Validates removing middle/first/last and noop removal.
## Callback System | ||
|
||
Getty provides a robust callback system that allows you to register and manage callback functions for session lifecycle events. This is particularly useful for cleanup operations, resource management, and custom event handling. | ||
|
||
### Key Features | ||
|
||
- **Thread-safe operations**: All callback operations are protected by mutex locks | ||
- **Replace semantics**: Adding a callback with the same handler and key will replace the existing one | ||
- **Panic safety**: Callback panics are properly handled and logged with stack traces | ||
- **Ordered execution**: Callbacks are executed in the order they were added | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doc vs code: Panic safety statement conflicts with implementation/tests.
Callbacks currently propagate panics; README says they’re recovered and logged. Align with the chosen behavior. I recommend adding recover in callbacks.Invoke (see suggested patch) and updating tests accordingly.
🤖 Prompt for AI Agents
In README.md around lines 23 to 33, the docs claim "Panic safety: Callback
panics are properly handled and logged with stack traces" but the code/tests
currently let panics propagate; to align behavior implement panic recovery
inside the callback invocation path (callbacks.Invoke) by wrapping each handler
call with a defer that recovers, logs the panic and stack trace, and prevents
propagation, while preserving ordered execution and mutex semantics; after
adding recover, update the tests to assert that panics do not escape Invoke and
that a log entry containing the panic and stack trace was produced (or
alternatively update the README to accurately reflect current behavior if you
prefer making docs change instead of code).
### Callback Management | ||
|
||
- **AddCloseCallback**: Register a callback to be executed when the session closes | ||
- **RemoveCloseCallback**: Remove a previously registered callback | ||
- **Thread Safety**: All operations are thread-safe and can be called concurrently | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Document comparable requirement for (handler, key).
Add a note: “handler and key must be comparable (e.g., string/int/pointer). Passing maps/slices will cause a runtime error; convert to a stable identifier first.”
🤖 Prompt for AI Agents
In README.md around lines 49 to 54, add a note to the Callback Management
section clarifying that the handler and key parameters must be comparable types
(for example string, int, or pointer) and that passing non-comparable types such
as maps or slices will cause a runtime error; instruct users to convert
non-comparable values to a stable identifier (e.g., serialized string, integer
ID, or pointer) before registering callbacks. Ensure the note is concise,
mentions examples, and is placed under the AddCloseCallback/RemoveCloseCallback
bullets so users see the requirement when using those APIs.
func TestCallbackInvokePanicPropagation(t *testing.T) { | ||
cb := &callbacks{} | ||
cb.Add("h", "k1", func() { panic("boom") }) | ||
|
||
// Test that panic is propagated (not swallowed by Invoke) | ||
defer func() { | ||
if r := recover(); r != nil { | ||
if r != "boom" { | ||
t.Errorf("Expected panic 'boom', got %v", r) | ||
} | ||
} else { | ||
t.Errorf("Expected panic to be propagated, but it was swallowed") | ||
} | ||
}() | ||
|
||
// This should panic and be caught by the defer above | ||
cb.Invoke() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update test to verify panic recovery (not propagation).
若采纳在 Invoke 中 recover 的建议,请将该测试改为“不会 panic,且后续回调继续执行”。示例补丁:
-func TestCallbackInvokePanicPropagation(t *testing.T) {
- cb := &callbacks{}
- cb.Add("h", "k1", func() { panic("boom") })
-
- // Test that panic is propagated (not swallowed by Invoke)
- defer func() {
- if r := recover(); r != nil {
- if r != "boom" {
- t.Errorf("Expected panic 'boom', got %v", r)
- }
- } else {
- t.Errorf("Expected panic to be propagated, but it was swallowed")
- }
- }()
-
- // This should panic and be caught by the defer above
- cb.Invoke()
-}
+func TestCallbackInvokePanicRecovery(t *testing.T) {
+ cb := &callbacks{}
+ called := 0
+ cb.Add("h", "k1", func() { panic("boom") })
+ cb.Add("h", "k2", func() { called++ })
+ // Should not panic; subsequent callbacks should still run.
+ cb.Invoke()
+ if called != 1 {
+ t.Fatalf("expected subsequent callbacks to run; got %d", called)
+ }
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func TestCallbackInvokePanicPropagation(t *testing.T) { | |
cb := &callbacks{} | |
cb.Add("h", "k1", func() { panic("boom") }) | |
// Test that panic is propagated (not swallowed by Invoke) | |
defer func() { | |
if r := recover(); r != nil { | |
if r != "boom" { | |
t.Errorf("Expected panic 'boom', got %v", r) | |
} | |
} else { | |
t.Errorf("Expected panic to be propagated, but it was swallowed") | |
} | |
}() | |
// This should panic and be caught by the defer above | |
cb.Invoke() | |
} | |
func TestCallbackInvokePanicRecovery(t *testing.T) { | |
cb := &callbacks{} | |
called := 0 | |
cb.Add("h", "k1", func() { panic("boom") }) | |
cb.Add("h", "k2", func() { called++ }) | |
// Should not panic; subsequent callbacks should still run. | |
cb.Invoke() | |
if called != 1 { | |
t.Fatalf("expected subsequent callbacks to run; got %d", called) | |
} | |
} |
🤖 Prompt for AI Agents
In transport/callback_test.go around lines 120 to 137, the test currently
expects a panic to be propagated from Invoke; update it to verify that Invoke
recovers from panics and continues executing subsequent callbacks: replace the
panic-propagation defer with a test that registers two callbacks (first panics,
second sets a bool flag), call cb.Invoke(), then assert no panic occurred by
simply letting the test run (a panic would fail the test) and verify the flag is
true using t.Fatalf/t.Errorf if it is false so the test ensures Invoke recovers
and continues executing remaining callbacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
README_CN.md (2)
31-33
: 文档与实现不一致:Panic 语义需与代码/测试统一。当前文档称“panic 会被正确处理并记录堆栈跟踪”,但此前实现与测试为“panic 直接冒泡”。请二选一并在文档中明确。建议先按现状修正文案(若未来实现 recover 再回改)。
建议补丁(若保持“冒泡”语义):
- - **Panic 安全性**:回调中的 panic 会被正确处理并记录堆栈跟踪 + - **Panic 语义**:回调中的 panic 将冒泡(由调用方处理)。如在 Session 层做 recover/记录,请在此注明具体位置与行为。可运行脚本快速验证当前仓库的实际语义(是否在 callbacks.Invoke/Session 中有 recover):
#!/bin/bash rg -nP 'func\s+(\([^)]*\)\s*)?Invoke\s*\(' -C3 --type go rg -n 'recover\(' -C2 --type go rg -n '\.Invoke\s*\(' -C2 --type go
53-56
: 补充“键类型可比较性(comparable)”约束,避免运行时 panic。实现使用“==”比较 handler/key,需提醒用户不要传入 map/slice/function 等不可比较类型。
建议在此小节追加一条要点:
- **RemoveCloseCallback**:移除之前注册的回调 - **线程安全**:所有操作都是线程安全的,可以并发调用 + - **键类型约束**:handler 和 key 必须是可比较(comparable)类型(如 string、int、指针)。请勿使用 map/slice/function。 + 如需复杂标识,建议使用稳定字符串或结构体指针作为标识。
🧹 Nitpick comments (1)
README_CN.md (1)
23-56
: 进一步澄清并发语义与 API 细节,减少歧义。
- 说明“执行期间的并发修改语义”:在一次关闭触发的执行中,对回调表的新增/移除是否影响“本次执行”(快照 vs. 实时)。
- 补充 API 签名片段,便于读者检索与 IDE 跳转:AddCloseCallback(handler, key any, cb func())、RemoveCloseCallback(handler, key any)。
可在“回调管理”末尾追加:
+ - **执行期间的一致性**:回调执行过程中对注册表的新增/移除对“本次执行”的影响语义为:<填写“按快照执行/实时可见”之一>。 + + 签名参考: + ```go + type CallBackFunc func() + func (s *Session) AddCloseCallback(handler, key any, cb CallBackFunc) + func (s *Session) RemoveCloseCallback(handler, key any) + ```
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
README.md
(1 hunks)README_CN.md
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- README.md
🧰 Additional context used
🧬 Code graph analysis (1)
README_CN.md (1)
transport/getty.go (2)
OnOpen
(68-94)ID
(97-110)
🔇 Additional comments (2)
README_CN.md (2)
21-22
: LGTM: 修复示例项目链接表述与格式。将裸链接改为显式 Markdown 链接更清晰、可读性更好。
49-49
: LGTM: 建议回调避免阻塞的注意事项到位。简明传达了性能与关闭时延的风险点。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
README_CN.md (1)
29-33
: Doc vs code: “Panic 安全性”与实现/测试不一致;请二选一并统一。
当前文档宣称会捕获/记录 panic(Line 31),但之前代码与测试表现为让 panic 冒泡。请按选型同步文档或代码;给出就地修订示例(若保持冒泡语义):- - **Panic 安全性**:回调中的 panic 会被正确处理并记录堆栈跟踪 + - **Panic 语义**:回调中的 panic 将冒泡,由调用方负责处理(例如在 Session 层或上层统一 recover)若要改为“每个回调独立 recover 并记录堆栈,同时不中断后续回调执行”,则需实现层面更新 callbacks.Invoke 与相应测试,并将此处描述改为“对每个回调做 recover 并记录堆栈,不中断后续回调”。
🧹 Nitpick comments (5)
README_CN.md (5)
32-33
: 明确执行顺序是 FIFO 还是 LIFO。
“有序执行”过于笼统,建议明确具体顺序,避免误解:- - **有序执行**:回调按照添加的顺序执行 + - **执行顺序**:回调按照添加的顺序执行(FIFO)如实现为栈式(头插),则应标注为 LIFO。
49-56
: 说明回调是在关闭路径中的同步/异步执行方式。
为便于使用者评估关闭时延与阻塞影响,请注明 Close 回调执行模型(同步于关闭流程/异步 goroutine、是否并行执行、是否有超时/截止时间)。可追加一句:“回调在会话关闭时于同一关闭流程中同步执行,建议快速返回;若需耗时处理,请另启 goroutine。”
53-55
: 补充方法签名,便于读者快速对齐用法。- - **AddCloseCallback**:注册一个在会话关闭时执行的回调 - - **RemoveCloseCallback**:移除之前注册的回调 + - **AddCloseCallback**:注册一个在会话关闭时执行的回调 + - **RemoveCloseCallback**:移除之前注册的回调 + +```go +// 回调函数类型 +type CloseCallback func() + +// 方法签名(示例) +AddCloseCallback(handler any, key any, cb CloseCallback) +RemoveCloseCallback(handler any, key any) bool +```
25-26
: 范围措辞更精确:当前仅提供“关闭回调”。
避免让读者误解已支持更多生命周期事件,建议加“目前提供关闭回调(CloseCallback)”字样。- Getty 提供了一个强大的回调系统,允许您为会话生命周期事件注册和管理回调函数。 + Getty 提供了一个强大的回调系统,允许您为会话生命周期事件注册和管理回调函数;当前提供“关闭回调(CloseCallback)”。
87-93
: 给出具体 API 名称与简短重试示例,提升可操作性。
建议点名常用发送 API 名称,并示例如何依据错误做上层重试/放弃:- 上层调用者需要根据这些结果决定是否加入重试机制。 + 上层调用者需要根据这些结果决定是否加入重试机制(例如基于 Session.WritePkg/Send/WriteBytes 的返回错误进行判断)。 @@ - 总之,Getty 的数据传输接口并不自带内部的重试机制;相反,是否在特定情况下实现重试逻辑由上层调用者决定。 + 示例: + ```go + if err := sess.WritePkg(msg, timeout); err != nil { + if errors.Is(err, syscall.EAGAIN) { // 发送缓冲区繁忙 + // 上层自行等待/退避后重试 + } else { + // 由自动重连/业务容错决定是否重试或丢弃 + } + } + ``` + 总之,Getty 的数据传输接口不自带内部重试;是否以及如何重试由上层决定。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
README.md
(1 hunks)README_CN.md
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- README.md
🧰 Additional context used
🧬 Code graph analysis (1)
README_CN.md (1)
transport/getty.go (2)
OnOpen
(68-94)ID
(97-110)
🔇 Additional comments (1)
README_CN.md (1)
21-22
: Example link fix looks good.
Link text and target are correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
README.md (2)
57-85
: Great: clear comparability guidance addresses earlier feedback.The supported/unsupported type lists and examples are accurate and helpful.
29-33
: Docs claim panic safety; confirm implementation or adjust text.README says panics are recovered and logged, but prior code/tests reportedly propagate panics. Align behavior or documentation.
Two alternative patches—pick the one that matches actual behavior:
Option A (recover-and-log is implemented):
- - **Panic safety**: Callback panics are properly handled and logged with stack traces + - **Panic safety**: Callback panics are recovered and logged with stack traces; panics do not escape invocationOption B (panics currently propagate):
- - **Panic safety**: Callback panics are properly handled and logged with stack traces + - **Panic behavior**: Callback panics propagate to the caller; use wrapper callbacks if you need recovery/loggingIf A: briefly document logger used and log level.
🧹 Nitpick comments (4)
README.md (4)
29-31
: Clarify replace semantics vs execution order.When replacing an existing (handler,key), does the callback keep its original position or move to the tail? Callers may rely on order guarantees.
34-47
: State the invocation model (serial vs parallel).Examples imply ordered execution. Explicitly say callbacks run serially in registration order and on which goroutine, to set latency expectations.
Apply:
// Callbacks are automatically executed when the session closes + +// Notes: +// - Callbacks run serially in registration order on a dedicated goroutine during shutdown. +// - A slow callback delays subsequent callbacks; offload heavy work to your own goroutines.
49-49
: Expand the non-blocking guidance with a one-liner.Mention that slow callbacks delay later ones if execution is serial.
-**Note**: Callbacks should be fast/non-blocking; move heavy work to separate goroutines to avoid delaying shutdown. +**Note**: Callbacks should be fast/non-blocking; because they execute in order, a slow callback delays later ones. Offload heavy work to separate goroutines.
51-56
: Document idempotency and reentrancy constraints.
- Is RemoveCloseCallback a no-op if the pair doesn’t exist?
- Are Add/Remove allowed during Invoke? If not, call it out to avoid deadlocks.
- **RemoveCloseCallback**: Remove a previously registered callback - **Thread Safety**: All operations are thread-safe and can be called concurrently +- **Idempotency**: RemoveCloseCallback is a no-op if the (handler, key) pair does not exist +- **During invocation**: Add/Remove are not applied to the in-flight invocation pass; they take effect on subsequent invocations (recommended)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
README.md
(1 hunks)README_CN.md
(1 hunks)transport/session.go
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- transport/session.go
- README_CN.md
🔇 Additional comments (1)
README.md (1)
21-22
: Link addition looks good; ensure consistency across languages.The examples link in the English README is correct. Please verify README_CN.md has the same target and anchor text so both docs stay in sync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
README.md (1)
29-33
: Panic-safety claim: align docs with behavior.Docs say panics are recovered and logged. Verify implementation/tests do this; otherwise adjust wording.
If code recovers panics, consider this doc tweak for precision:
- **Panic safety**: Callback panics are properly handled and logged with stack traces + **Panic safety**: Each callback runs with panic recovery; panics are recovered, logged (with stack traces), and do not stop subsequent callbacksIf panics currently propagate, change to:
- **Panic safety**: Callback panics are properly handled and logged with stack traces + **Panic behavior**: Panics propagate to the caller; use application-level recovery if needed
🧹 Nitpick comments (4)
README.md (4)
49-50
: Clarify order vs goroutine semantics.To avoid ambiguity, state that callbacks run sequentially within a single goroutine to preserve ordering.
- **Note**: Callbacks are executed in a separate goroutine during session shutdown. + **Note**: During session shutdown, callbacks are executed sequentially in a dedicated goroutine to preserve the add-order.
53-56
: Document Remove semantics and idempotency.Spell out behavior when the key isn’t found and whether Remove is idempotent/what it returns (if anything).
- **RemoveCloseCallback**: Remove a previously registered callback + **RemoveCloseCallback**: Remove a previously registered callback (no-op if not found; safe to call multiple times)
29-31
: “Replace semantics”: specify position after replacement.Does replacement keep the original position or move the entry to the tail? Make it explicit to prevent surprises.
- **Replace semantics**: Adding a callback with the same handler and key will replace the existing one + **Replace semantics**: Adding with the same (handler, key) replaces the existing callback in place (position preserved). + If your implementation moves it to the end, document that instead.
61-68
: Caveat for float/complex keys.These are comparable but error‑prone (NaN != NaN; rounding). Recommend discouraging them as identifiers.
- **Basic types**: `string`, `int`, ... `float32`, `float64`, `bool`, `complex64`, `complex128` + **Basic types**: `string`, `int`, ... `float32`, `float64`, `bool`, `complex64`, `complex128` + - ⚠️ Avoid `float*`/`complex*` as keys due to NaN and precision semantics; prefer strings/ints.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
README.md
(1 hunks)README_CN.md
(1 hunks)transport/callback.go
(1 hunks)transport/callback_test.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- transport/callback.go
- README_CN.md
- transport/callback_test.go
🔇 Additional comments (3)
README.md (3)
21-22
: Examples link update looks good.Good switch to getty-examples.
Please confirm README_CN.md also points to the same repo and correct example paths.
64-65
: Interface comparability: note Go version/implementation detail.If you rely on reflect.Type.Comparable (Go 1.20+), note the minimum Go version or the fallback strategy to avoid runtime panics.
Please confirm the helper checks comparability before equality, e.g., via reflect.Type.Comparable or equivalent guard, and logs at a consistent level (warn/error). If yes, add a brief note.
34-47
: Usage snippet reads well.Concise and accurate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
README.md (5)
29-33
: Clarify where panic recovery happens to avoid overpromising.Document that recovery/logging is performed by the session close path (goroutine with defer/recover), not by a generic Invoke. This keeps README consistent with implementation and tests.
Apply this wording tweak:
- - **Panic safety**: Callback panics are properly handled and logged with stack traces + - **Panic safety**: During session close, callbacks run in a dedicated goroutine with defer/recover; panics are logged with stack traces and do not escape the close path
49-50
: Strengthen the note with explicit panic‑recovery behavior.This removes ambiguity about where ordering and recovery are enforced.
-**Note**: During session shutdown, callbacks are executed sequentially in a dedicated goroutine to preserve the add-order. +**Note**: During session shutdown, callbacks are executed sequentially in a dedicated goroutine to preserve add‑order, with defer/recover to log panics without letting them escape the close path.
36-47
: Minor example polish: show that removal is optional and idempotent.Add a short comment to signal it’s safe to call Remove even if not present.
// Remove a specific callback -session.RemoveCloseCallback("cleanup", "resources") +// Safe to call even if the pair was never added (no-op) +session.RemoveCloseCallback("cleanup", "resources")
23-24
: PR hygiene: consider updating the PR title to reflect both link fixes and close‑callback docs.E.g., “Docs: fix example links and add per‑session close‑callback docs (EN/ZN)”.
57-86
: README: "non‑comparable are logged and ignored" is inaccurate — comparability is checked but no log is emitted.
- Verified: comparability is enforced in transport/callback.go (uses reflect.TypeOf(v).Comparable()); AddCloseCallback delegates to s.closeCallback.Add(...).
- Missing: I found no logging at the rejection path — non‑comparable values are detected and skipped but not logged; callbacks use "==" for lookup (callback.go).
- Recommendation: either remove the "logged" claim and replace the exhaustive type list with a concise rule ("values must be comparable — see Go spec for comparison rules"), or add an explicit log at the rejection point (transport/callback.go).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
README.md
(1 hunks)README_CN.md
(1 hunks)transport/session_callback.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- README_CN.md
- transport/session_callback.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ayamzh
PR: AlexStocks/getty#91
File: README_CN.md:0-0
Timestamp: 2025-09-18T08:16:03.103Z
Learning: In Getty's callback system, while callbacks.Invoke() propagates panics, the session layer in transport/session.go wraps the callback invocation in a goroutine with defer/recover to handle panics safely and log them with stack traces, making the "Panic 安全性" documentation in README accurate.
Learnt from: ayamzh
PR: AlexStocks/getty#91
File: README_CN.md:0-0
Timestamp: 2025-09-18T08:16:03.103Z
Learning: In Getty's callback system, while callbacks.Invoke() propagates panics, the session layer in transport/session.go wraps the callback invocation in a goroutine with defer/recover to handle panics safely and log them with stack traces, making the "Panic 安全性" documentation in README accurate.
📚 Learning: 2025-09-18T08:16:03.103Z
Learnt from: ayamzh
PR: AlexStocks/getty#91
File: README_CN.md:0-0
Timestamp: 2025-09-18T08:16:03.103Z
Learning: In Getty's callback system, while callbacks.Invoke() propagates panics, the session layer in transport/session.go wraps the callback invocation in a goroutine with defer/recover to handle panics safely and log them with stack traces, making the "Panic 安全性" documentation in README accurate.
Applied to files:
README.md
🔇 Additional comments (2)
README.md (2)
21-22
: Examples link fix looks good.The repo link is correct and resolves the long‑standing misdirection to examples.
23-55
: Docs addition addresses prior feedback; ensure README_CN mirrors the same guarantees.This section satisfies the “add a description of the callback in the README” ask. Please confirm the Chinese README contains the same scope/wording (panic recovery location, ordering, idempotent remove).
What this PR does:
Fix incorrect example project jump links in the Chinese README
A CloseCallback functionality has been added to the session, intended for resource reclamation (or cleanup) when the connection is closed.
Which issue(s) this PR fixes:
Fixes #
Special notes for your reviewer:
nothing
Does this PR introduce a user-facing change?:
no
Summary by CodeRabbit
New Features
Documentation
Tests