Fix race conditions and improve lifecycle safety (#150)
## Summary Comprehensive fixes for race conditions, concurrency bugs, and code quality improvements in the lifecycle module and related test files. ## Changes ### Race Condition Fixes - Fixed data race in `SetChannel()` and `Channel()` by adding mutex protection - Fixed data race in `StartedAt()` by adding mutex protection - Fixed test race conditions in `transport` and `interaction` packages where variables were shared between goroutines ### Concurrency Safety Improvements - Refactored `Close()` to release mutex before calling external code, preventing potential deadlocks - Made `SetChannel()` reject calls after `Close()` to prevent setting channel on torn-down lifecycle - Made `SetStatus()` ignore calls after `Close()` to ensure CLOSED is a terminal state - Added nil check to `SetChannel()` to prevent masking upstream bugs ### Code Quality Improvements - Refactored `Close()` to extract helper methods: `closeChannel()`, `closeConnection()`, `cleanupRegistry()`, `cleanupForwarder()` - Fixed `isClosedError()` to remove redundant string comparison - Added `PortRegistry` interface for better interface segregation (removed dependency on full `port.Port`) - Made `cleanupRegistry()` conditional on non-empty slug to avoid unnecessary registry calls - Fixed `startedAt` to be set when session starts running instead of at object creation Reviewed-on: #150 Co-authored-by: Bagas <bagas@fossy.my.id> Co-committed-by: Bagas <bagas@fossy.my.id>
This commit was merged in pull request #150.
This commit is contained in:
@@ -13,7 +13,6 @@ import (
|
||||
"tunnel_pls/internal/session/slug"
|
||||
"tunnel_pls/internal/types"
|
||||
|
||||
"tunnel_pls/internal/port"
|
||||
"tunnel_pls/internal/registry"
|
||||
|
||||
proto "git.fossy.my.id/bagas/tunnel-please-grpc/gen"
|
||||
@@ -885,16 +884,16 @@ func (m *mockLifecycle) Connection() ssh.Conn {
|
||||
return args.Get(0).(ssh.Conn)
|
||||
}
|
||||
func (m *mockLifecycle) User() string { return m.Called().String(0) }
|
||||
func (m *mockLifecycle) SetChannel(channel ssh.Channel) { m.Called(channel) }
|
||||
func (m *mockLifecycle) SetChannel(channel ssh.Channel) error { return m.Called(channel).Error(0) }
|
||||
func (m *mockLifecycle) SetStatus(status types.SessionStatus) { m.Called(status) }
|
||||
func (m *mockLifecycle) IsActive() bool { return m.Called().Bool(0) }
|
||||
func (m *mockLifecycle) StartedAt() time.Time { return m.Called().Get(0).(time.Time) }
|
||||
func (m *mockLifecycle) PortRegistry() port.Port {
|
||||
func (m *mockLifecycle) PortRegistry() lifecycle.PortRegistry {
|
||||
args := m.Called()
|
||||
if args.Get(0) == nil {
|
||||
return nil
|
||||
}
|
||||
return args.Get(0).(port.Port)
|
||||
return args.Get(0).(lifecycle.PortRegistry)
|
||||
}
|
||||
|
||||
type mockEventServiceClient struct {
|
||||
|
||||
Reference in New Issue
Block a user