Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,28 @@ type Session interface {
- **`Conn()`**: Get the underlying network connection object
- **`IsClosed()`**: Check if the session is closed
- **`Close()`**: Close the session connection
- **`Reset()`**: Reset session state
- **`Reset()`**: Close and reset the session after managed work and connection cleanup finish. If any managed callback of this session is active at entry, Reset schedules cleanup and returns immediately, including calls from external goroutines. Otherwise it waits. The signature is unchanged, but completion semantics change while callbacks are active.
- **`TryReset()`** (optional `TryResetter`): Return `ErrResetDuringCallback` without requesting reset if any callback of this session is active at entry; otherwise wait and return the reset result.
- **`ResetAsync()`** (optional `AsyncResetter`): Request cleanup without blocking. Each call returns a separate buffered channel that receives one error (`nil` on success) and then closes. Pending requests share one cleanup operation, but later resets cannot overwrite their results.

`Session` keeps its original `Reset()` signature. The optional interfaces do not require existing custom Session implementations to add methods. Stop starting new operations before waiting for completion or reusing the session. Never wait for reset inside a callback of the session being reset; request it and return instead:

```go
func (l *listener) OnClose(s getty.Session) {
async, ok := s.(getty.AsyncResetter)
if !ok {
return
}
done := async.ResetAsync()
go func() {
if err := <-done; err != nil {
return // Reset failed; do not recycle the session.
}
// Session cleanup and reset completed successfully.
}()
// Return so the reset worker can finish waiting for this callback.
}
```

##### Configuration Settings
- **`SetName(string)`**: Set session name
Expand Down
23 changes: 22 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,28 @@ type Session interface {
- **`Conn()`**: 获取底层网络连接对象
- **`IsClosed()`**: 检查会话是否已关闭
- **`Close()`**: 关闭会话连接
- **`Reset()`**: 重置会话状态
- **`Reset()`**: 关闭会话,等待受管理工作和连接清理结束后重置状态。如果调用时本 Session 有任何受管理回调正在执行,则发起重置后立即返回,外部 goroutine 的调用也一样;否则同步等待。原有签名保持不变,但回调活跃期间的完成语义发生变化。
- **`TryReset()`**(可选 `TryResetter`):如果调用时本 Session 有回调正在执行,返回 `ErrResetDuringCallback`,不发起重置;否则等待并返回本次重置结果。
- **`ResetAsync()`**(可选 `AsyncResetter`):不阻塞地请求清理。每次调用返回独立的缓冲 channel,发送一次 error(成功为 `nil`)后关闭。并发未完成请求共享一次清理,但结果不会被后续重置覆盖。

`Session` 保持原有 `Reset()` 签名,可选接口无需现有自定义 Session 实现新增方法。在等待完成或复用会话前,应停止发起新操作。不能在被重置 Session 的回调内等待完成,应发起请求后返回:

```go
func (l *listener) OnClose(s getty.Session) {
async, ok := s.(getty.AsyncResetter)
if !ok {
return
}
done := async.ResetAsync()
go func() {
if err := <-done; err != nil {
return // Reset failed; do not recycle the session.
}
// 会话清理和重置成功完成,现在可以回收。
}()
// 返回,让重置任务能够结束对本回调的等待。
}
```

##### 配置设置
- **`SetName(string)`**: 设置会话名称
Expand Down
6 changes: 5 additions & 1 deletion transport/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,11 @@ func TestUDPClient(t *testing.T) {

clt.Close()
assert.True(t, clt.IsClosed())
msgHandler.array[0].Reset()
async, ok := msgHandler.array[0].(AsyncResetter)
if !ok {
t.Fatal("built-in session does not implement AsyncResetter")
}
waitForReset(t, async.ResetAsync())
assert.Nil(t, msgHandler.array[0].Conn())
// ss.WritePkg([]byte("hello"), 0)
}
Expand Down
31 changes: 27 additions & 4 deletions transport/getty.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ import (
)

var (
ErrSessionClosed = perrors.New("session Already Closed")
ErrSessionBlocked = perrors.New("session Full Blocked")
ErrNullPeerAddr = perrors.New("peer address is nil")
// ErrResetDuringCallback is returned by TryResetter.TryReset when it is
// called while any managed callback of the target session is active. Use ResetAsync and
// observe completion outside the callback instead.
ErrResetDuringCallback = perrors.New("cannot synchronously reset a session while a callback is active")
ErrSessionClosed = perrors.New("session Already Closed")
ErrSessionBlocked = perrors.New("session Full Blocked")
ErrNullPeerAddr = perrors.New("peer address is nil")
)

// NewSessionCallback will be invoked when server accepts a new client connection or client connects to server successfully.
Expand Down Expand Up @@ -64,7 +68,10 @@ type ReadWriter interface {
Writer
}

// EventListener is used to process pkg that received from remote session
// EventListener processes session events. Inside a callback, Session.Reset
// schedules the reset and returns; it must not wait for the callback to finish.
// Use an AsyncResetter to observe completion, or a TryResetter to get
// ErrResetDuringCallback while any callback of this session is active.
type EventListener interface {
// OnOpen invoked when session opened
// If the return error is not nil, @Session will be closed.
Expand Down Expand Up @@ -93,6 +100,22 @@ type EventListener interface {
OnMessage(Session, any)
}

// AsyncResetter requests reset without blocking. Each call returns a separate
// buffered channel that receives one error (nil on success) and then closes.
// Concurrent pending requests share cleanup work, but retain their own result.
// Success means managed work, connection cleanup, and field reset have finished.
// Never wait for the result inside a callback of the session being reset.
type AsyncResetter interface {
ResetAsync() <-chan error
}

// TryResetter reports ErrResetDuringCallback without requesting reset if any
// managed callback of this session is active at entry, regardless of the caller's
// goroutine. Otherwise it waits for reset and returns that operation's result.
type TryResetter interface {
TryReset() error
}

// EndPoint represents the identity of the client/server
type EndPoint interface {
// ID get EndPoint ID
Expand Down
Loading
Loading