-
Notifications
You must be signed in to change notification settings - Fork 0
⚡ Async NotifyClient in Worker #8
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| package worker | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/adcondev/ticket-daemon/internal/server" | ||
| "github.com/coder/websocket" | ||
| ) | ||
|
|
||
| // mockSlowNotifier simulates a slow network connection | ||
| type mockSlowNotifier struct { | ||
| delay time.Duration | ||
| } | ||
|
|
||
| func (m *mockSlowNotifier) NotifyClient(_ *websocket.Conn, _ server.Response) error { | ||
| time.Sleep(m.delay) | ||
| return nil | ||
| } | ||
|
|
||
| func TestWorkerBlockingNotification(t *testing.T) { | ||
| // Setup | ||
| jobCount := 5 | ||
| notifier := &mockSlowNotifier{delay: 200 * time.Millisecond} // 200ms delay per notification | ||
|
|
||
| // Create job queue | ||
| jobQueue := make(chan *server.PrintJob, jobCount) | ||
|
|
||
| // Create worker | ||
| config := Config{DefaultPrinter: "test"} | ||
| w := NewWorker(jobQueue, notifier, config) | ||
|
|
||
| // Start worker | ||
| w.Start() | ||
| defer w.Stop() | ||
|
|
||
| // Create dummy connection (we need a non-nil pointer) | ||
| dummyConn := &websocket.Conn{} | ||
|
|
||
| // Prepare jobs | ||
| for j := 0; j < jobCount; j++ { | ||
| job := &server.PrintJob{ | ||
| ID: "test-job", | ||
| ClientConn: dummyConn, | ||
| Document: json.RawMessage("{}"), // Invalid document to trigger failure but still notify | ||
| ReceivedAt: time.Now(), | ||
| } | ||
| jobQueue <- job | ||
| } | ||
|
|
||
| start := time.Now() | ||
|
|
||
| // Wait for processing | ||
| deadline := time.Now().Add(5 * time.Second) | ||
| for { | ||
| stats := w.Stats() | ||
| if stats.JobsProcessed+stats.JobsFailed >= int64(jobCount) { | ||
| break | ||
| } | ||
| if time.Now().After(deadline) { | ||
| t.Fatalf("Timeout waiting for jobs to process. Processed: %d, Failed: %d", stats.JobsProcessed, stats.JobsFailed) | ||
| } | ||
| time.Sleep(10 * time.Millisecond) | ||
| } | ||
|
|
||
| duration := time.Since(start) | ||
|
|
||
| // With blocking notification: 5 jobs * 200ms = 1000ms (1s) | ||
| // We expect it to take at least 1s. | ||
| if duration > 500*time.Millisecond { | ||
| t.Errorf("Expected duration < 500ms (async), got %v", duration) | ||
|
Comment on lines
+52
to
+72
|
||
| } else { | ||
| t.Logf("Blocking verified: Duration %v for %d jobs", duration, jobCount) | ||
| } | ||
|
Comment on lines
+22
to
+75
|
||
| } | ||
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.
Spawning a goroutine per job for notifications means Worker.Stop() no longer waits for in-flight notifications. During shutdown this can leave background goroutines running while the WebSocket server is being closed, and notifications may continue up to the 5s timeout in NotifyClient. Consider tracking notification goroutines with a WaitGroup (and waiting in Stop), or sending notifications via a bounded queue/worker to avoid leaks during shutdown.