fix(daemon): publish deadline before invalidation hook
- commit
- a710b5136fa24f0b8e17cb9f39d183ef72fc8c0a
- author
- brice · · 2026-07-11 20:03 UTC
- parent
- 5c0dde8
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +15 -3
M internal/usecase/daemon/render_coordinator.go +15 -3
| @@ -276,10 +276,10 @@ func (c *renderCoordinator) invalidateForAttachment(source *attachedClient, inv | |||
| 276 | 276 | c.armed = c.armed || arm | |
| 277 | 277 | c.mu.Unlock() | |
| 278 | 278 | stopTimer(old) | |
| 279 | - | if onInvalidate != nil { | |
| 280 | - | onInvalidate(inv) | |
| 281 | - | } | |
| 282 | 279 | if !arm || clock == nil { | |
| 280 | + | if onInvalidate != nil { | |
| 281 | + | onInvalidate(inv) | |
| 282 | + | } | |
| 283 | 283 | return | |
| 284 | 284 | } | |
| 285 | 285 | ||
| @@ -297,11 +297,17 @@ func (c *renderCoordinator) invalidateForAttachment(source *attachedClient, inv | |||
| 297 | 297 | c.mu.Unlock() | |
| 298 | 298 | if !valid { | |
| 299 | 299 | stopTimer(timer) | |
| 300 | + | if onInvalidate != nil { | |
| 301 | + | onInvalidate(inv) | |
| 302 | + | } | |
| 300 | 303 | return | |
| 301 | 304 | } | |
| 302 | 305 | if timerC == nil { | |
| 303 | 306 | stopTimer(timer) | |
| 304 | 307 | c.fire(gen, false, true) | |
| 308 | + | if onInvalidate != nil { | |
| 309 | + | onInvalidate(inv) | |
| 310 | + | } | |
| 305 | 311 | return | |
| 306 | 312 | } | |
| 307 | 313 | go func() { | |
| @@ -313,6 +319,12 @@ func (c *renderCoordinator) invalidateForAttachment(source *attachedClient, inv | |||
| 313 | 319 | case <-cancel: | |
| 314 | 320 | } | |
| 315 | 321 | }() | |
| 322 | + | // Test-visible observation follows deadline publication, so a producer | |
| 323 | + | // callback cannot observe a successful invalidation before its timer owns | |
| 324 | + | // a worker (and race tests cannot finish while a mock expectation remains). | |
| 325 | + | if onInvalidate != nil { | |
| 326 | + | onInvalidate(inv) | |
| 327 | + | } | |
| 316 | 328 | runtime.Gosched() | |
| 317 | 329 | } | |
| 318 | 330 | ||
| @@ -276,10 +276,10 @@ func (c *renderCoordinator) invalidateForAttachment(source *attachedClient, inv | |||||
| 276 | c.armed = c.armed || arm | 276 | c.armed = c.armed || arm | ||
| 277 | c.mu.Unlock() | 277 | c.mu.Unlock() | ||
| 278 | stopTimer(old) | 278 | stopTimer(old) | ||
| 279 | - | if onInvalidate != nil { | |||
| 280 | - | onInvalidate(inv) | |||
| 281 | - | } | |||
| 282 | if !arm || clock == nil { | 279 | if !arm || clock == nil { | ||
| 280 | + | if onInvalidate != nil { | |||
| 281 | + | onInvalidate(inv) | |||
| 282 | + | } | |||
| 283 | return | 283 | return | ||
| 284 | } | 284 | } | ||
| 285 | 285 | ||||
| @@ -297,11 +297,17 @@ func (c *renderCoordinator) invalidateForAttachment(source *attachedClient, inv | |||||
| 297 | c.mu.Unlock() | 297 | c.mu.Unlock() | ||
| 298 | if !valid { | 298 | if !valid { | ||
| 299 | stopTimer(timer) | 299 | stopTimer(timer) | ||
| 300 | + | if onInvalidate != nil { | |||
| 301 | + | onInvalidate(inv) | |||
| 302 | + | } | |||
| 300 | return | 303 | return | ||
| 301 | } | 304 | } | ||
| 302 | if timerC == nil { | 305 | if timerC == nil { | ||
| 303 | stopTimer(timer) | 306 | stopTimer(timer) | ||
| 304 | c.fire(gen, false, true) | 307 | c.fire(gen, false, true) | ||
| 308 | + | if onInvalidate != nil { | |||
| 309 | + | onInvalidate(inv) | |||
| 310 | + | } | |||
| 305 | return | 311 | return | ||
| 306 | } | 312 | } | ||
| 307 | go func() { | 313 | go func() { | ||
| @@ -313,6 +319,12 @@ func (c *renderCoordinator) invalidateForAttachment(source *attachedClient, inv | |||||
| 313 | case <-cancel: | 319 | case <-cancel: | ||
| 314 | } | 320 | } | ||
| 315 | }() | 321 | }() | ||
| 322 | + | // Test-visible observation follows deadline publication, so a producer | |||
| 323 | + | // callback cannot observe a successful invalidation before its timer owns | |||
| 324 | + | // a worker (and race tests cannot finish while a mock expectation remains). | |||
| 325 | + | if onInvalidate != nil { | |||
| 326 | + | onInvalidate(inv) | |||
| 327 | + | } | |||
| 316 | runtime.Gosched() | 328 | runtime.Gosched() | ||
| 317 | } | 329 | } | ||
| 318 | 330 | ||||