-
Notifications
You must be signed in to change notification settings - Fork 8
Open
Description
client.Destroy() Hangs in Streaming Mode (~25% of the time)
Summary
client.Destroy() hangs for 10+ seconds approximately 25% of the time when using streaming mode. The SSE reader goroutine remains blocked on a network read and never exits.
Reproduction
main.go:
package main
import (
"log"
"os"
"github.com/splitio/go-client/v6/splitio/client"
"github.com/splitio/go-client/v6/splitio/conf"
)
func main() {
apiKey := os.Getenv("SPLIT_API_KEY")
if apiKey == "" {
log.Fatal("SPLIT_API_KEY required")
}
cfg := conf.Default()
factory, err := client.NewSplitFactory(apiKey, cfg)
if err != nil {
log.Fatal(err)
}
splitClient := factory.Client()
if err := splitClient.BlockUntilReady(10); err != nil {
log.Fatal(err)
}
log.Println("Split SDK ready")
// Evaluate a treatment
treatment := splitClient.Treatment("user-123", "my-feature", nil)
log.Printf("Treatment: %s\n", treatment)
log.Println("Calling Destroy()...")
// THIS HANGS ~25% OF THE TIME
splitClient.Destroy()
log.Println("Destroy() completed")
}Run 20 times to reproduce:
export SPLIT_API_KEY="your-api-key"
for i in {1..20}; do
echo "=== Run $i ==="
timeout 15s go run main.go
if [ $? -eq 124 ]; then
echo "TIMEOUT - HANG DETECTED"
fi
doneExpected Behavior
Destroy() completes in ~100-200ms:
Split SDK ready
Treatment: control
Calling Destroy()...
SSE streaming exiting
Stopped streaming
Destroy() completed
Actual Behavior (25% of runs)
Hangs for 10+ seconds:
Split SDK ready
Treatment: control
Calling Destroy()...
Stopping all synchronization tasks
SSE client stopped or shutdown in progress. Ignoring.
[hangs until timeout kills it]
Test Results
| Metric | Value |
|---|---|
| Total runs | 20 |
| Hangs detected | 5 |
| Failure rate | 25% |
| Hang duration | 10+ seconds (or up to 1 hour without timeout) |
Stack Trace During Hang
SSE reader goroutine blocked waiting for server data:
goroutine 103 [sync.Cond.Wait]:
bufio.(*Reader).ReadString()
/opt/homebrew/opt/go/libexec/src/bufio/bufio.go:502
github.com/splitio/go-toolkit/v5/sse.(*Client).readEvents()
go-toolkit/v5@v5.4.1/sse/sse.go:55
Main goroutine waiting for shutdown:
goroutine 54 [sync.Cond.Wait]:
github.com/splitio/go-toolkit/v5/struct/traits/lifecycle.(*Manager).AwaitShutdownComplete()
go-toolkit/v5@v5.4.1/struct/traits/lifecycle/lifecycle.go:85
github.com/splitio/go-split-commons/v8/synchronizer.(*ManagerImpl).Stop()
go-split-commons/v8@v8.0.0/synchronizer/manager.go:184
github.com/splitio/go-client/v6/splitio/client.(*SplitFactory).Destroy()
go-client/v6@v6.8.1/splitio/client/factory.go:252
The SSE reader never receives the shutdown signal and waits indefinitely for server data. The HTTP/2 connection remains open until timeout (up to 1 hour).
Environment
- SDK:
github.com/splitio/go-client/v6@v6.8.1 - Commons:
github.com/splitio/go-split-commons/v8@v8.0.0 - Toolkit:
github.com/splitio/go-toolkit/v5@v5.4.1 - Go: 1.25.4
- Mode: Streaming (default with valid API key)
Impact
- Production application shutdowns hang 25% of the time
- Goroutine and connection leaks
Metadata
Metadata
Assignees
Labels
No labels