@@ -1374,13 +1374,10 @@ func TestSerialExecution_Sync(t *testing.T) {
13741374 current := executing .Add (1 )
13751375 defer executing .Add (- 1 )
13761376
1377- // Track maximum concurrent executions
1377+ // Track maximum concurrent executions atomically
13781378 for {
13791379 max := maxConcurrent .Load ()
1380- if current <= max {
1381- break
1382- }
1383- if maxConcurrent .CompareAndSwap (max , current ) {
1380+ if current <= max || maxConcurrent .CompareAndSwap (max , current ) {
13841381 break
13851382 }
13861383 }
@@ -1431,13 +1428,10 @@ func TestSerialExecution_Async(t *testing.T) {
14311428 current := executing .Add (1 )
14321429 defer executing .Add (- 1 )
14331430
1434- // Track maximum concurrent executions
1431+ // Track maximum concurrent executions atomically
14351432 for {
14361433 max := maxConcurrent .Load ()
1437- if current <= max {
1438- break
1439- }
1440- if maxConcurrent .CompareAndSwap (max , current ) {
1434+ if current <= max || maxConcurrent .CompareAndSwap (max , current ) {
14411435 break
14421436 }
14431437 }
@@ -1549,7 +1543,7 @@ func TestSerialExecution_WithNonSerial(t *testing.T) {
15491543 current := executingSerial .Add (1 )
15501544 defer executingSerial .Add (- 1 )
15511545
1552- // Track maximum concurrent executions
1546+ // Track maximum concurrent executions atomically
15531547 for {
15541548 max := maxConcurrentSerial .Load ()
15551549 if current <= max || maxConcurrentSerial .CompareAndSwap (max , current ) {
@@ -1566,7 +1560,7 @@ func TestSerialExecution_WithNonSerial(t *testing.T) {
15661560 current := executingNonSerial .Add (1 )
15671561 defer executingNonSerial .Add (- 1 )
15681562
1569- // Track maximum concurrent executions
1563+ // Track maximum concurrent executions atomically
15701564 for {
15711565 max := maxConcurrentNonSerial .Load ()
15721566 if current <= max || maxConcurrentNonSerial .CompareAndSwap (max , current ) {
@@ -1624,13 +1618,10 @@ func TestSerialExecution_CopyBehavior(t *testing.T) {
16241618 current := executing .Add (1 )
16251619 defer executing .Add (- 1 )
16261620
1627- // Track maximum concurrent executions
1621+ // Track maximum concurrent executions atomically
16281622 for {
16291623 max := maxConcurrent .Load ()
1630- if current <= max {
1631- break
1632- }
1633- if maxConcurrent .CompareAndSwap (max , current ) {
1624+ if current <= max || maxConcurrent .CompareAndSwap (max , current ) {
16341625 break
16351626 }
16361627 }
@@ -1684,13 +1675,10 @@ func TestAsyncExecution_Basic(t *testing.T) {
16841675 current := executing .Add (1 )
16851676 defer executing .Add (- 1 )
16861677
1687- // Track maximum concurrent executions
1678+ // Track maximum concurrent executions atomically
16881679 for {
16891680 max := maxConcurrent .Load ()
1690- if current <= max {
1691- break
1692- }
1693- if maxConcurrent .CompareAndSwap (max , current ) {
1681+ if current <= max || maxConcurrent .CompareAndSwap (max , current ) {
16941682 break
16951683 }
16961684 }
@@ -1731,95 +1719,6 @@ func TestAsyncExecution_Basic(t *testing.T) {
17311719 assert .GreaterOrEqual (t , maxConcurrent .Load (), int32 (2 ), "At least 2 handlers should execute concurrently in async mode" )
17321720}
17331721
1734- // TestAsyncExecution_WorkerPool tests that async handlers use worker pool
1735- func TestAsyncExecution_WorkerPool (t * testing.T ) {
1736- ctx := context .Background ()
1737-
1738- // Create a custom worker pool with limited workers
1739- poolCfg := ants .DefaultConfig ()
1740- poolCfg .NumWorkers = 3
1741- pool , err := workerpool .New [workerpooltypes.Pool ](ctx , poolCfg )
1742- require .NoError (t , err )
1743- require .NoError (t , pool .Start (ctx ))
1744- defer pool .Shutdown (ctx )
1745-
1746- cfg := & Config {
1747- WorkerPool : pool ,
1748- PreAllocHandlers : 16 ,
1749- }
1750- const numWorkers = 3 // Track the worker pool size for assertions
1751- bus , err := NewEventBus [string ](ctx , cfg )
1752- require .NoError (t , err )
1753- defer bus .Close (ctx )
1754-
1755- var executing atomic.Int32
1756- var maxConcurrent atomic.Int32
1757- var callCount atomic.Int32
1758-
1759- // Channels to coordinate handler execution
1760- handlerStarted := make (chan struct {}, 20 )
1761- handlerCanFinish := make (chan struct {})
1762-
1763- handler := func (ctx context.Context , event string ) (Result , error ) {
1764- callCount .Add (1 )
1765- current := executing .Add (1 )
1766- defer executing .Add (- 1 )
1767-
1768- // Track maximum concurrent executions
1769- for {
1770- max := maxConcurrent .Load ()
1771- if current <= max {
1772- break
1773- }
1774- if maxConcurrent .CompareAndSwap (max , current ) {
1775- break
1776- }
1777- }
1778-
1779- // Signal that this handler has started
1780- handlerStarted <- struct {}{}
1781-
1782- // Wait for signal to finish (simulates work while limiting by worker pool)
1783- <- handlerCanFinish
1784-
1785- return Result {}, nil
1786- }
1787-
1788- // Subscribe with Async option
1789- _ , err = bus .Subscribe (handler , bus .WithAsync ())
1790- require .NoError (t , err )
1791-
1792- // Publish many events at once - async handlers should not block
1793- const numPublish = 20
1794- for i := 0 ; i < numPublish ; i ++ {
1795- bus .Publish (ctx , "event" )
1796- }
1797-
1798- // Wait for worker pool to fill up (numWorkers handlers should be executing)
1799- // We expect to see at least 3 handlers running concurrently (the worker pool size)
1800- for i := 0 ; i < numWorkers ; i ++ {
1801- <- handlerStarted
1802- }
1803-
1804- // At this point, worker pool should be at capacity
1805- // Now allow all handlers to finish
1806- close (handlerCanFinish )
1807-
1808- bus .WaitAsync () // Wait for all async handlers to complete
1809-
1810- // Verify: All events were processed
1811- assert .Equal (t , int32 (numPublish ), callCount .Load (), "All events should be processed" )
1812-
1813- // Verify: Maximum concurrent executions limited by worker pool size
1814- // Should be at most numWorkers (3)
1815- assert .LessOrEqual (t , maxConcurrent .Load (), int32 (numWorkers ),
1816- "Concurrent executions should be limited by worker pool size" )
1817-
1818- // We explicitly waited for numWorkers handlers to start, so we know concurrency occurred
1819- assert .GreaterOrEqual (t , maxConcurrent .Load (), int32 (numWorkers ),
1820- "Should see at least numWorkers handlers executing concurrently" )
1821- }
1822-
18231722// TestAsyncExecution_ErrorHandling tests async handlers with errors
18241723func TestAsyncExecution_ErrorHandling (t * testing.T ) {
18251724 ctx := context .Background ()
@@ -2573,17 +2472,17 @@ func TestPublish(t *testing.T) {
25732472 name : "publish to multiple async subscribers" ,
25742473 config : * DefaultConfig (),
25752474 setupFunc : func (t * testing.T , bus * EventBus [string ]) {
2576- receivedCount := 0
2475+ receivedCount := new ( int64 )
25772476 for i := 0 ; i < 5 ; i ++ {
25782477 _ , err := bus .Subscribe (func (ctx context.Context , event string ) (Result , error ) {
2579- receivedCount ++
2478+ atomic . AddInt64 ( receivedCount , 1 )
25802479 return Result {}, nil
25812480 }, bus .WithAsync ())
25822481 require .NoError (t , err )
25832482 }
25842483 t .Cleanup (func () {
25852484 bus .WaitAsync ()
2586- assert .Equal (t , 5 , receivedCount )
2485+ assert .Equal (t , int64 ( 5 ), * receivedCount )
25872486 })
25882487 },
25892488 publishFunc : func (t * testing.T , bus * EventBus [string ]) {
@@ -2598,7 +2497,7 @@ func TestPublish(t *testing.T) {
25982497 config : * DefaultConfig (),
25992498 setupFunc : func (t * testing.T , bus * EventBus [string ]) {
26002499 syncCount := 0
2601- asyncCount := 0
2500+ asyncCount := new ( int64 )
26022501 // Add 3 sync subscribers
26032502 for i := 0 ; i < 3 ; i ++ {
26042503 _ , err := bus .Subscribe (func (ctx context.Context , event string ) (Result , error ) {
@@ -2610,15 +2509,15 @@ func TestPublish(t *testing.T) {
26102509 // Add 3 async subscribers
26112510 for i := 0 ; i < 3 ; i ++ {
26122511 _ , err := bus .Subscribe (func (ctx context.Context , event string ) (Result , error ) {
2613- asyncCount ++
2512+ atomic . AddInt64 ( asyncCount , 1 )
26142513 return Result {}, nil
26152514 }, bus .WithAsync ())
26162515 require .NoError (t , err )
26172516 }
26182517 t .Cleanup (func () {
26192518 bus .WaitAsync ()
26202519 assert .Equal (t , 3 , syncCount )
2621- assert .Equal (t , 3 , asyncCount )
2520+ assert .Equal (t , int64 ( 3 ), * asyncCount )
26222521 })
26232522 },
26242523 publishFunc : func (t * testing.T , bus * EventBus [string ]) {
@@ -3533,6 +3432,7 @@ func TestPublishWithHooks(t *testing.T) {
35333432
35343433 _ , err = bus .Subscribe (func (ctx context.Context , event string ) (Result , error ) {
35353434 handlerCallCount .Add (1 )
3435+ time .Sleep (10 * time .Millisecond )
35363436 return Result {}, nil
35373437 })
35383438 require .NoError (t , err )
@@ -3629,6 +3529,7 @@ func TestPublishWithHooks(t *testing.T) {
36293529
36303530 _ , err = bus .Subscribe (func (ctx context.Context , event string ) (Result , error ) {
36313531 handlerCallCount .Add (1 )
3532+ time .Sleep (10 * time .Millisecond )
36323533 return Result {}, nil
36333534 }, bus .WithAfter (func (ctx context.Context , event string , id SubscriptionID , result Result , duration time.Duration , err error ) {
36343535 assert .Equal (t , int32 (1 ), handlerCallCount .Load (), "after hook should be called after handler" )
0 commit comments