This guide provides comprehensive strategies and implementations for detecting deadlocks in the ship-go codebase. The tests target specific concurrency issues identified in the codebase analysis.
- Use Case: Always enable for all concurrency tests
- Command:
go test -race -v ./... - Effectiveness: Essential baseline, catches data races but not deadlocks
- Use Case: Integration tests and specific deadlock scenarios
- Implementation: See
TestDeadlockScenarioWithTimeoutin deadlock_detection_test.go - Effectiveness: Good for known problematic patterns
- Use Case: Development and debugging phase
- Implementation: Replace sync.Mutex with deadlock.Mutex
- Effectiveness: Best for finding lock ordering issues
- Use Case: Finding rare timing-dependent issues
- Implementation: See
TestStressWithMetricstests - Effectiveness: Good for production-like scenarios
- Use Case: Systematic exploration of state space
- Implementation: See property_based_deadlock_test.go
- Effectiveness: Excellent for finding edge cases
Issue: setState() holds mux while calling timer methods that need handshakeTimerMux
Test: TestSetStateTimerDeadlock
Solution: Release mux before timer operations or use lock-free timer state
Issue: Gap between checking and modifying connection map
Test: TestConnectionRegistrationRace
Solution: Atomic UnregisterConnectionIfMatch method
Issue: Timer state changes during concurrent operations
Test: TestTimerLifecycleRaceConditions
Solution: Atomic timer operations with proper state tracking
# Run all deadlock detection tests with race detector
go test -race -v -run "Deadlock|Race" ./...
# Run specific test suites
go test -race -v -run TestSetStateTimerDeadlock ./ship
go test -race -v -run TestHubMutexOrderingDeadlock ./hub
go test -race -v -run TestPropertyBased ./ship
# Run with timeout detection
go test -race -v -timeout 30s -run "Deadlock" ./...# Run stress tests with extended duration
go test -race -v -run TestStress -timeout 5m ./...
# Run with CPU profiling to identify contention
go test -race -v -run TestStress -cpuprofile=cpu.prof ./ship
go tool pprof cpu.prof# CI-friendly command with coverage
go test -race -v -coverprofile=coverage.out -covermode=atomic \
-run "Deadlock|Race|Stress" ./...- Test Timeout: Tests hanging indicate potential deadlock
- High Contention: Metric showing >1% contention suggests lock conflicts
- Race Detector Output: Data race warnings may indicate improper synchronization
- Inconsistent State: Final state not matching expected indicates race conditions
- Operation Latency: Operations taking >10ms indicate contention
- Success Rates: Operations failing due to state conflicts
- Contention Events: Frequency of lock contention
- State Consistency: Invariant violations
- Add deadlock tests to CI pipeline
- Enable race detector for all tests
- Monitor test execution times
# Pre-commit hook
#!/bin/bash
go test -race -short -run "Deadlock|Race" ./...- Add mutex contention metrics
- Monitor goroutine counts
- Track operation latencies
- TestSetStateTimerDeadlock - Critical path deadlock
- TestConnectionRegistrationRace - Data loss scenario
- TestStressWithMetrics - Production-like load
- TestPropertyBasedDeadlockDetection - Edge case discovery
- CI Time: +2-3 minutes per test run
- Memory: 2-3x normal test memory with race detector
- Development Time: 1-2 days initial implementation
- Bug Prevention: Catch deadlocks before production
- Performance: Identify contention bottlenecks
- Reliability: Ensure concurrent operations are safe
- Confidence: Refactor with safety net
// Force specific timing to reproduce deadlocks
runtime.Gosched() // Yield to other goroutines
time.Sleep(time.Microsecond) // Add controlled delays// Use go-deadlock with custom configuration
deadlock.Opts.DeadlockTimeout = 100 * time.Millisecond
deadlock.Opts.MaxMapSize = 10000// Check goroutine count before/after tests
before := runtime.NumGoroutine()
// Run test
after := runtime.NumGoroutine()
assert.Equal(t, before, after, "Goroutine leak detected")- Flaky Tests: Increase timeouts or use deterministic scheduling
- False Positives: Verify actual deadlock vs slow operations
- Race Detector Overhead: Use -short flag for quick checks
- CI Timeouts: Split tests into parallel jobs
# Generate blocking profile
go test -race -blockprofile=block.prof -v ./...
go tool pprof block.prof
# Trace execution
go test -race -trace=trace.out -v -run TestSpecific ./...
go tool trace trace.outThese deadlock detection tests provide comprehensive coverage of known concurrency issues in ship-go. Regular execution and monitoring of these tests will significantly improve the reliability and performance of concurrent operations.