github.com/m3db/m3@v1.5.0/src/msg/producer/writer/message_writer_test.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package writer 22 23 import ( 24 "net" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/fortytw2/leaktest" 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/require" 32 "github.com/uber-go/tally" 33 34 "github.com/m3db/m3/src/msg/producer" 35 "github.com/m3db/m3/src/x/instrument" 36 "github.com/m3db/m3/src/x/retry" 37 xtest "github.com/m3db/m3/src/x/test" 38 ) 39 40 func TestMessageWriterRandomIndex(t *testing.T) { 41 indexes := make([]int, 10) 42 reset := func() { 43 for i := range indexes { 44 indexes[i] = i 45 } 46 } 47 48 reset() 49 firstIdx := randIndex(indexes, len(indexes)-1) 50 for { 51 reset() 52 newIdx := randIndex(indexes, len(indexes)-1) 53 // Make sure the first index is random. 54 if firstIdx != newIdx { 55 break 56 } 57 time.Sleep(50 * time.Millisecond) 58 } 59 60 reset() 61 idx1 := randIndex(indexes, len(indexes)-1) 62 idx2 := randIndex(indexes, len(indexes)-2) 63 for { 64 reset() 65 newIdx1 := randIndex(indexes, len(indexes)-1) 66 newIdx2 := randIndex(indexes, len(indexes)-2) 67 // Make sure the order is random. 68 if idx2-idx1 != newIdx2-newIdx1 { 69 break 70 } 71 time.Sleep(50 * time.Millisecond) 72 } 73 } 74 75 func TestMessageWriterRandomFullIteration(t *testing.T) { 76 indexes := make([]int, 100) 77 var indexMap map[int]struct{} 78 reset := func() { 79 for i := range indexes { 80 indexes[i] = i 81 } 82 indexMap = make(map[int]struct{}, 100) 83 } 84 85 for n := 0; n < 1000; n++ { 86 reset() 87 for i := len(indexes) - 1; i >= 0; i-- { 88 idx := randIndex(indexes, i) 89 indexMap[idx] = struct{}{} 90 } 91 require.Equal(t, 100, len(indexMap)) 92 } 93 } 94 95 func TestMessageWriterWithPooling(t *testing.T) { 96 defer leaktest.Check(t)() 97 98 lis, err := net.Listen("tcp", "127.0.0.1:0") 99 require.NoError(t, err) 100 defer lis.Close() 101 102 addr := lis.Addr().String() 103 opts := testOptions() 104 105 var wg sync.WaitGroup 106 defer wg.Wait() 107 108 wg.Add(1) 109 go func() { 110 testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions()) 111 wg.Done() 112 }() 113 114 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl) 115 require.Equal(t, 200, int(w.ReplicatedShardID())) 116 w.Init() 117 118 a := newAckRouter(1) 119 a.Register(200, w) 120 121 cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics()) 122 cw.Init() 123 defer cw.Close() 124 125 w.AddConsumerWriter(cw) 126 127 ctrl := xtest.NewController(t) 128 defer ctrl.Finish() 129 130 mm1 := producer.NewMockMessage(ctrl) 131 mm1.EXPECT().Bytes().Return([]byte("foo")).Times(1) 132 mm1.EXPECT().Size().Return(3).Times(1) 133 mm1.EXPECT().Finalize(producer.Consumed) 134 135 w.Write(producer.NewRefCountedMessage(mm1, nil)) 136 137 for { 138 w.RLock() 139 l := w.queue.Len() 140 w.RUnlock() 141 if l == 0 { 142 break 143 } 144 time.Sleep(100 * time.Millisecond) 145 } 146 require.Equal(t, 0, w.queue.Len()) 147 w.RemoveConsumerWriter(addr) 148 149 mm2 := producer.NewMockMessage(ctrl) 150 mm2.EXPECT().Bytes().Return([]byte("bar")).Times(1) 151 mm2.EXPECT().Size().Return(3).Times(1) 152 153 w.Write(producer.NewRefCountedMessage(mm2, nil)) 154 for { 155 if !isEmptyWithLock(w.acks) { 156 break 157 } 158 time.Sleep(100 * time.Millisecond) 159 } 160 require.Equal(t, 1, w.queue.Len()) 161 162 mm2.EXPECT().Finalize(producer.Consumed) 163 w.Ack(metadata{metadataKey: metadataKey{shard: 200, id: 2}}) 164 require.True(t, isEmptyWithLock(w.acks)) 165 for { 166 w.RLock() 167 l := w.queue.Len() 168 w.RUnlock() 169 if l == 0 { 170 break 171 } 172 time.Sleep(100 * time.Millisecond) 173 } 174 w.Close() 175 w.Close() 176 } 177 178 func TestMessageWriterWithoutPooling(t *testing.T) { 179 defer leaktest.Check(t)() 180 181 lis, err := net.Listen("tcp", "127.0.0.1:0") 182 require.NoError(t, err) 183 defer lis.Close() 184 185 addr := lis.Addr().String() 186 opts := testOptions() 187 188 var wg sync.WaitGroup 189 defer wg.Wait() 190 191 wg.Add(1) 192 go func() { 193 testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions()) 194 wg.Done() 195 }() 196 197 w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl) 198 require.Equal(t, 200, int(w.ReplicatedShardID())) 199 w.Init() 200 201 a := newAckRouter(1) 202 a.Register(200, w) 203 204 cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics()) 205 cw.Init() 206 defer cw.Close() 207 208 w.AddConsumerWriter(cw) 209 210 ctrl := xtest.NewController(t) 211 defer ctrl.Finish() 212 213 mm1 := producer.NewMockMessage(ctrl) 214 mm1.EXPECT().Bytes().Return([]byte("foo")).Times(1) 215 mm1.EXPECT().Size().Return(3).Times(1) 216 mm1.EXPECT().Finalize(producer.Consumed) 217 218 w.Write(producer.NewRefCountedMessage(mm1, nil)) 219 220 for { 221 w.RLock() 222 l := w.queue.Len() 223 w.RUnlock() 224 if l == 0 { 225 break 226 } 227 time.Sleep(100 * time.Millisecond) 228 } 229 require.Equal(t, 0, w.queue.Len()) 230 w.RemoveConsumerWriter(addr) 231 232 mm2 := producer.NewMockMessage(ctrl) 233 mm2.EXPECT().Bytes().Return([]byte("bar")).Times(1) 234 mm2.EXPECT().Size().Return(3).Times(1) 235 236 w.Write(producer.NewRefCountedMessage(mm2, nil)) 237 for { 238 if !isEmptyWithLock(w.acks) { 239 break 240 } 241 time.Sleep(100 * time.Millisecond) 242 } 243 require.Equal(t, 1, w.queue.Len()) 244 245 mm2.EXPECT().Finalize(producer.Consumed) 246 w.Ack(metadata{metadataKey: metadataKey{shard: 200, id: 2}}) 247 require.True(t, isEmptyWithLock(w.acks)) 248 for { 249 w.RLock() 250 l := w.queue.Len() 251 w.RUnlock() 252 if l == 0 { 253 break 254 } 255 time.Sleep(100 * time.Millisecond) 256 } 257 w.Close() 258 w.Close() 259 } 260 261 func TestMessageWriterRetryWithoutPooling(t *testing.T) { 262 defer leaktest.Check(t)() 263 264 lis, err := net.Listen("tcp", "127.0.0.1:0") 265 require.NoError(t, err) 266 defer lis.Close() 267 268 addr := lis.Addr().String() 269 opts := testOptions() 270 w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl) 271 w.Init() 272 defer w.Close() 273 274 a := newAckRouter(1) 275 a.Register(200, w) 276 277 ctrl := xtest.NewController(t) 278 defer ctrl.Finish() 279 280 mm := producer.NewMockMessage(ctrl) 281 mm.EXPECT().Bytes().Return([]byte("foo")).AnyTimes() 282 mm.EXPECT().Size().Return(3).Times(1) 283 mm.EXPECT().Finalize(producer.Consumed) 284 285 rm := producer.NewRefCountedMessage(mm, nil) 286 w.Write(rm) 287 288 w.AddConsumerWriter(newConsumerWriter("bad", a, opts, testConsumerWriterMetrics())) 289 require.Equal(t, 1, w.queue.Len()) 290 291 for { 292 if !isEmptyWithLock(w.acks) { 293 break 294 } 295 time.Sleep(100 * time.Millisecond) 296 } 297 298 _, ok := w.acks.ackMap[metadataKey{shard: 200, id: 1}] 299 require.True(t, ok) 300 301 cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics()) 302 cw.Init() 303 defer cw.Close() 304 305 w.AddConsumerWriter(cw) 306 go func() { 307 testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions()) 308 }() 309 310 for { 311 w.Lock() 312 l := w.queue.Len() 313 w.Unlock() 314 if l == 0 { 315 break 316 } 317 time.Sleep(100 * time.Millisecond) 318 } 319 } 320 321 func TestMessageWriterRetryWithPooling(t *testing.T) { 322 defer leaktest.Check(t)() 323 324 lis, err := net.Listen("tcp", "127.0.0.1:0") 325 require.NoError(t, err) 326 defer lis.Close() 327 328 addr := lis.Addr().String() 329 opts := testOptions() 330 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl) 331 w.Init() 332 defer w.Close() 333 334 a := newAckRouter(1) 335 a.Register(200, w) 336 337 ctrl := xtest.NewController(t) 338 defer ctrl.Finish() 339 340 mm := producer.NewMockMessage(ctrl) 341 mm.EXPECT().Bytes().Return([]byte("foo")).AnyTimes() 342 mm.EXPECT().Size().Return(3).Times(1) 343 mm.EXPECT().Finalize(producer.Consumed) 344 345 rm := producer.NewRefCountedMessage(mm, nil) 346 w.Write(rm) 347 348 w.AddConsumerWriter(newConsumerWriter("bad", a, opts, testConsumerWriterMetrics())) 349 require.Equal(t, 1, w.queue.Len()) 350 351 for { 352 if !isEmptyWithLock(w.acks) { 353 break 354 } 355 time.Sleep(100 * time.Millisecond) 356 } 357 358 m1, ok := w.acks.ackMap[metadataKey{shard: 200, id: 1}] 359 require.True(t, ok) 360 361 cw := newConsumerWriter(addr, a, opts, testConsumerWriterMetrics()) 362 cw.Init() 363 defer cw.Close() 364 365 w.AddConsumerWriter(cw) 366 go func() { 367 testConsumeAndAckOnConnectionListener(t, lis, opts.EncoderOptions(), opts.DecoderOptions()) 368 }() 369 370 for { 371 w.Lock() 372 l := w.queue.Len() 373 w.Unlock() 374 if l == 0 { 375 break 376 } 377 time.Sleep(100 * time.Millisecond) 378 } 379 380 // A get will NOT allocate a new message because the old one has been returned to pool. 381 m := w.mPool.Get() 382 require.Equal(t, m1, m) 383 require.True(t, m.IsDroppedOrConsumed()) 384 } 385 386 func TestMessageWriterCleanupDroppedMessage(t *testing.T) { 387 defer leaktest.Check(t)() 388 389 opts := testOptions() 390 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()) 391 392 ctrl := xtest.NewController(t) 393 defer ctrl.Finish() 394 395 mm := producer.NewMockMessage(ctrl) 396 397 mm.EXPECT().Size().Return(3).Times(1) 398 rm := producer.NewRefCountedMessage(mm, nil) 399 mm.EXPECT().Finalize(producer.Dropped) 400 rm.Drop() 401 mm.EXPECT().Bytes().Return([]byte("foo")) 402 w.Write(rm) 403 404 // A get will allocate a new message because the old one has not been returned to pool yet. 405 m := w.(*messageWriterImpl).mPool.Get() 406 require.Nil(t, m.RefCountedMessage) 407 408 require.Equal(t, 1, w.(*messageWriterImpl).queue.Len()) 409 w.Init() 410 defer w.Close() 411 412 for { 413 w.(*messageWriterImpl).Lock() 414 l := w.(*messageWriterImpl).queue.Len() 415 w.(*messageWriterImpl).Unlock() 416 if l != 1 { 417 break 418 } 419 time.Sleep(100 * time.Millisecond) 420 } 421 require.True(t, isEmptyWithLock(w.(*messageWriterImpl).acks)) 422 423 // A get will NOT allocate a new message because the old one has been returned to pool. 424 m = w.(*messageWriterImpl).mPool.Get() 425 require.True(t, m.IsDroppedOrConsumed()) 426 } 427 428 func TestMessageWriterCleanupAckedMessage(t *testing.T) { 429 defer leaktest.Check(t)() 430 431 opts := testOptions() 432 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl) 433 w.Init() 434 defer w.Close() 435 436 ctrl := xtest.NewController(t) 437 defer ctrl.Finish() 438 439 mm := producer.NewMockMessage(ctrl) 440 mm.EXPECT().Bytes().Return([]byte("foo")) 441 mm.EXPECT().Size().Return(3).Times(1) 442 443 rm := producer.NewRefCountedMessage(mm, nil) 444 // Another message write also holds this message. 445 rm.IncRef() 446 447 w.Write(rm) 448 for { 449 if !isEmptyWithLock(w.acks) { 450 break 451 } 452 time.Sleep(100 * time.Millisecond) 453 } 454 acks := w.acks 455 meta := metadata{ 456 metadataKey: metadataKey{ 457 id: 1, 458 shard: 200, 459 }, 460 } 461 // The message will not be finalized because it's still being hold by another message writer. 462 acks.ack(meta) 463 require.True(t, isEmptyWithLock(w.acks)) 464 465 // A get will allocate a new message because the old one has not been returned to pool yet. 466 m := w.mPool.Get() 467 require.Nil(t, m.RefCountedMessage) 468 require.Equal(t, 1, w.queue.Len()) 469 470 for { 471 w.Lock() 472 l := w.queue.Len() 473 w.Unlock() 474 if l != 1 { 475 break 476 } 477 time.Sleep(100 * time.Millisecond) 478 } 479 480 // A get will NOT allocate a new message because the old one has been returned to pool. 481 m = w.mPool.Get() 482 require.Equal(t, meta, m.Metadata()) 483 } 484 485 func TestMessageWriterCutoverCutoff(t *testing.T) { 486 ctrl := xtest.NewController(t) 487 defer ctrl.Finish() 488 489 w := newMessageWriter(200, testMessagePool(testOptions()), nil, testMessageWriterMetrics()).(*messageWriterImpl) 490 now := time.Now() 491 w.nowFn = func() time.Time { return now } 492 require.True(t, w.isValidWriteWithLock(now.UnixNano())) 493 require.True(t, w.isValidWriteWithLock(now.UnixNano()+150)) 494 require.True(t, w.isValidWriteWithLock(now.UnixNano()+250)) 495 require.True(t, w.isValidWriteWithLock(now.UnixNano()+50)) 496 497 w.SetCutoffNanos(now.UnixNano() + 200) 498 w.SetCutoverNanos(now.UnixNano() + 100) 499 require.True(t, w.isValidWriteWithLock(now.UnixNano()+150)) 500 require.False(t, w.isValidWriteWithLock(now.UnixNano()+250)) 501 require.False(t, w.isValidWriteWithLock(now.UnixNano()+50)) 502 require.Equal(t, 0, w.queue.Len()) 503 504 mm := producer.NewMockMessage(ctrl) 505 mm.EXPECT().Size().Return(3) 506 w.Write(producer.NewRefCountedMessage(mm, nil)) 507 require.Equal(t, 0, w.queue.Len()) 508 } 509 510 func TestMessageWriterIgnoreCutoverCutoff(t *testing.T) { 511 ctrl := xtest.NewController(t) 512 defer ctrl.Finish() 513 514 opts := NewOptions().SetIgnoreCutoffCutover(true) 515 516 w := newMessageWriter(200, testMessagePool(testOptions()), opts, testMessageWriterMetrics()).(*messageWriterImpl) 517 now := time.Now() 518 w.nowFn = func() time.Time { return now } 519 520 w.SetCutoffNanos(now.UnixNano() + 200) 521 w.SetCutoverNanos(now.UnixNano() + 100) 522 require.True(t, w.isValidWriteWithLock(now.UnixNano()+150)) 523 require.True(t, w.isValidWriteWithLock(now.UnixNano()+250)) 524 require.True(t, w.isValidWriteWithLock(now.UnixNano()+50)) 525 require.Equal(t, 0, w.queue.Len()) 526 527 mm := producer.NewMockMessage(ctrl) 528 mm.EXPECT().Bytes().Return([]byte("foo")) 529 mm.EXPECT().Size().Return(3) 530 w.Write(producer.NewRefCountedMessage(mm, nil)) 531 require.Equal(t, 1, w.queue.Len()) 532 } 533 534 func TestMessageWriterKeepNewWritesInOrderInFrontOfTheQueue(t *testing.T) { 535 ctrl := xtest.NewController(t) 536 defer ctrl.Finish() 537 538 opts := testOptions().SetMessageRetryNanosFn( 539 NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)), 540 ) 541 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl) 542 543 now := time.Now() 544 w.nowFn = func() time.Time { return now } 545 546 mm1 := producer.NewMockMessage(ctrl) 547 mm1.EXPECT().Size().Return(3) 548 rm1 := producer.NewRefCountedMessage(mm1, nil) 549 mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes() 550 w.Write(rm1) 551 validateMessages(t, []*producer.RefCountedMessage{rm1}, w) 552 mm2 := producer.NewMockMessage(ctrl) 553 mm2.EXPECT().Size().Return(3) 554 rm2 := producer.NewRefCountedMessage(mm2, nil) 555 mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes() 556 w.Write(rm2) 557 validateMessages(t, []*producer.RefCountedMessage{rm1, rm2}, w) 558 w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), 2, true, &scanBatchMetrics{}) 559 560 w.lastNewWrite = nil 561 mm3 := producer.NewMockMessage(ctrl) 562 mm3.EXPECT().Size().Return(3) 563 rm3 := producer.NewRefCountedMessage(mm3, nil) 564 mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes() 565 w.Write(rm3) 566 validateMessages(t, []*producer.RefCountedMessage{rm3, rm1, rm2}, w) 567 568 mm4 := producer.NewMockMessage(ctrl) 569 mm4.EXPECT().Size().Return(3) 570 rm4 := producer.NewRefCountedMessage(mm4, nil) 571 mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes() 572 w.Write(rm4) 573 574 validateMessages(t, []*producer.RefCountedMessage{rm3, rm4, rm1, rm2}, w) 575 } 576 577 func TestMessageWriterRetryIterateBatchFullScan(t *testing.T) { 578 ctrl := xtest.NewController(t) 579 defer ctrl.Finish() 580 581 retryBatchSize := 2 582 opts := testOptions().SetMessageQueueScanBatchSize(retryBatchSize).SetMessageRetryNanosFn( 583 NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)), 584 ) 585 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl) 586 587 now := time.Now() 588 w.nowFn = func() time.Time { return now } 589 590 mm1 := producer.NewMockMessage(ctrl) 591 mm1.EXPECT().Size().Return(3) 592 rm1 := producer.NewRefCountedMessage(mm1, nil) 593 mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes() 594 w.Write(rm1) 595 596 mm2 := producer.NewMockMessage(ctrl) 597 mm2.EXPECT().Size().Return(3) 598 rm2 := producer.NewRefCountedMessage(mm2, nil) 599 mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes() 600 w.Write(rm2) 601 602 mm3 := producer.NewMockMessage(ctrl) 603 mm3.EXPECT().Size().Return(3) 604 rm3 := producer.NewRefCountedMessage(mm3, nil) 605 mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes() 606 w.Write(rm3) 607 608 mm4 := producer.NewMockMessage(ctrl) 609 mm4.EXPECT().Size().Return(3) 610 rm4 := producer.NewRefCountedMessage(mm4, nil) 611 mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes() 612 w.Write(rm4) 613 614 validateMessages(t, []*producer.RefCountedMessage{rm1, rm2, rm3, rm4}, w) 615 mm1.EXPECT().Finalize(gomock.Eq(producer.Dropped)) 616 rm1.Drop() 617 require.Equal(t, 4, w.queue.Len()) 618 e, toBeRetried := w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{}) 619 require.Equal(t, 1, len(toBeRetried)) 620 require.Equal(t, 3, w.queue.Len()) 621 622 // Make sure it stopped at rm3. 623 require.Equal(t, rm3, e.Value.(*message).RefCountedMessage) 624 625 require.Equal(t, 3, w.queue.Len()) 626 e, toBeRetried = w.scanBatchWithLock(e, w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{}) 627 require.Nil(t, e) 628 require.Equal(t, 2, len(toBeRetried)) 629 require.Equal(t, 3, w.queue.Len()) 630 631 e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{}) 632 // Make sure it stopped at rm4. 633 require.Equal(t, rm4, e.Value.(*message).RefCountedMessage) 634 require.Equal(t, 0, len(toBeRetried)) 635 636 e, toBeRetried = w.scanBatchWithLock(e, w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{}) 637 require.Nil(t, e) 638 require.Equal(t, 0, len(toBeRetried)) 639 } 640 641 //nolint:lll 642 func TestMessageWriterRetryIterateBatchFullScanWithMessageTTL(t *testing.T) { 643 ctrl := xtest.NewController(t) 644 defer ctrl.Finish() 645 646 retryBatchSize := 2 647 opts := testOptions().SetMessageQueueScanBatchSize(retryBatchSize).SetMessageRetryNanosFn( 648 NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)), 649 ) 650 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl) 651 652 now := time.Now() 653 w.nowFn = func() time.Time { return now } 654 655 mm1 := producer.NewMockMessage(ctrl) 656 mm1.EXPECT().Size().Return(3) 657 rm1 := producer.NewRefCountedMessage(mm1, nil) 658 mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes() 659 w.Write(rm1) 660 661 mm2 := producer.NewMockMessage(ctrl) 662 mm2.EXPECT().Size().Return(3) 663 rm2 := producer.NewRefCountedMessage(mm2, nil) 664 mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes() 665 w.Write(rm2) 666 667 mm3 := producer.NewMockMessage(ctrl) 668 mm3.EXPECT().Size().Return(3) 669 rm3 := producer.NewRefCountedMessage(mm3, nil) 670 mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes() 671 w.Write(rm3) 672 673 mm4 := producer.NewMockMessage(ctrl) 674 mm4.EXPECT().Size().Return(3) 675 rm4 := producer.NewRefCountedMessage(mm4, nil) 676 mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes() 677 w.Write(rm4) 678 679 mm1.EXPECT().Finalize(gomock.Eq(producer.Dropped)) 680 rm1.Drop() 681 require.Equal(t, 4, w.queue.Len()) 682 e, toBeRetried := w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, true, &scanBatchMetrics{}) 683 require.Equal(t, 1, len(toBeRetried)) 684 require.Equal(t, 3, w.queue.Len()) 685 686 require.Equal(t, rm2, e.Value.(*message).RefCountedMessage) 687 688 w.SetMessageTTLNanos(int64(time.Minute)) 689 mm4.EXPECT().Finalize(gomock.Eq(producer.Consumed)) 690 mm3.EXPECT().Finalize(gomock.Eq(producer.Consumed)) 691 e, toBeRetried = w.scanBatchWithLock(e, w.nowFn().UnixNano()+int64(time.Hour), retryBatchSize, true, &scanBatchMetrics{}) 692 require.Equal(t, 0, len(toBeRetried)) 693 require.Equal(t, 1, w.queue.Len()) 694 require.Nil(t, e) 695 696 mm2.EXPECT().Finalize(gomock.Eq(producer.Consumed)) 697 e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano()+int64(time.Hour), retryBatchSize, true, &scanBatchMetrics{}) 698 require.Equal(t, 0, len(toBeRetried)) 699 require.Equal(t, 0, w.queue.Len()) 700 require.Nil(t, e) 701 } 702 703 //nolint:lll 704 func TestMessageWriterRetryIterateBatchNotFullScan(t *testing.T) { 705 ctrl := xtest.NewController(t) 706 defer ctrl.Finish() 707 708 retryBatchSize := 100 709 opts := testOptions().SetMessageQueueScanBatchSize(retryBatchSize).SetMessageRetryNanosFn( 710 NextRetryNanosFn(retry.NewOptions().SetInitialBackoff(2 * time.Nanosecond).SetMaxBackoff(5 * time.Nanosecond)), 711 ) 712 w := newMessageWriter(200, testMessagePool(opts), opts, testMessageWriterMetrics()).(*messageWriterImpl) 713 714 now := time.Now() 715 w.nowFn = func() time.Time { return now } 716 717 mm1 := producer.NewMockMessage(ctrl) 718 mm1.EXPECT().Size().Return(1) 719 rm1 := producer.NewRefCountedMessage(mm1, nil) 720 mm1.EXPECT().Bytes().Return([]byte("1")).AnyTimes() 721 w.Write(rm1) 722 723 mm2 := producer.NewMockMessage(ctrl) 724 mm2.EXPECT().Size().Return(1) 725 rm2 := producer.NewRefCountedMessage(mm2, nil) 726 mm2.EXPECT().Bytes().Return([]byte("2")).AnyTimes() 727 w.Write(rm2) 728 729 mm3 := producer.NewMockMessage(ctrl) 730 mm3.EXPECT().Size().Return(1) 731 rm3 := producer.NewRefCountedMessage(mm3, nil) 732 mm3.EXPECT().Bytes().Return([]byte("3")).AnyTimes() 733 w.Write(rm3) 734 735 mm4 := producer.NewMockMessage(ctrl) 736 mm4.EXPECT().Size().Return(1) 737 rm4 := producer.NewRefCountedMessage(mm4, nil) 738 mm4.EXPECT().Bytes().Return([]byte("4")).AnyTimes() 739 w.Write(rm4) 740 741 mm1.EXPECT().Finalize(gomock.Eq(producer.Dropped)) 742 rm1.Drop() 743 require.Equal(t, 4, w.queue.Len()) 744 e, toBeRetried := w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, false, &scanBatchMetrics{}) 745 require.Equal(t, 3, len(toBeRetried)) 746 require.Equal(t, 3, w.queue.Len()) 747 require.Nil(t, e) 748 validateMessages(t, []*producer.RefCountedMessage{rm2, rm3, rm4}, w) 749 // Although mm4 is dropped, it will not be removed from the queue because 750 // it was not checked. 751 mm4.EXPECT().Finalize(gomock.Eq(producer.Dropped)) 752 rm4.Drop() 753 require.Equal(t, 3, w.queue.Len()) 754 e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, false, &scanBatchMetrics{}) 755 require.Equal(t, rm2, e.Value.(*message).RefCountedMessage) 756 require.Equal(t, 0, len(toBeRetried)) 757 require.Equal(t, 3, w.queue.Len()) 758 require.Equal(t, rm2, e.Value.(*message).RefCountedMessage) 759 validateMessages(t, []*producer.RefCountedMessage{rm2, rm3, rm4}, w) 760 w.lastNewWrite = nil 761 762 mm5 := producer.NewMockMessage(ctrl) 763 mm5.EXPECT().Size().Return(1) 764 rm5 := producer.NewRefCountedMessage(mm5, nil) 765 mm5.EXPECT().Bytes().Return([]byte("5")).AnyTimes() 766 w.Write(rm5) 767 validateMessages(t, []*producer.RefCountedMessage{rm5, rm2, rm3, rm4}, w) 768 769 require.Equal(t, 4, w.queue.Len()) 770 e, toBeRetried = w.scanBatchWithLock(w.queue.Front(), w.nowFn().UnixNano(), retryBatchSize, false, &scanBatchMetrics{}) 771 require.Equal(t, rm2, e.Value.(*message).RefCountedMessage) 772 require.Equal(t, 1, len(toBeRetried)) 773 require.Equal(t, rm5, toBeRetried[0].RefCountedMessage) 774 require.Equal(t, 4, w.queue.Len()) 775 } 776 777 func TestNextRetryAfterNanos(t *testing.T) { 778 backoffDuration := time.Minute 779 opts := testOptions(). 780 SetMessageRetryNanosFn( 781 NextRetryNanosFn( 782 retry.NewOptions(). 783 SetInitialBackoff(backoffDuration). 784 SetMaxBackoff(2 * backoffDuration). 785 SetJitter(true), 786 ), 787 ) 788 w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl) 789 790 nowNanos := time.Now().UnixNano() 791 m := newMessage() 792 m.IncWriteTimes() 793 retryAtNanos := w.nextRetryAfterNanos(m.WriteTimes()) + nowNanos 794 require.True(t, retryAtNanos > nowNanos) 795 require.True(t, retryAtNanos < nowNanos+int64(backoffDuration)) 796 797 m.IncWriteTimes() 798 retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes()) + nowNanos 799 require.True(t, retryAtNanos >= nowNanos+int64(backoffDuration)) 800 require.True(t, retryAtNanos < nowNanos+2*int64(backoffDuration)) 801 802 m.IncWriteTimes() 803 retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes()) + nowNanos 804 require.True(t, retryAtNanos == nowNanos+2*int64(backoffDuration)) 805 } 806 807 func TestStaticRetryAfterNanos(t *testing.T) { 808 fn, err := StaticRetryNanosFn([]time.Duration{time.Minute, 10 * time.Second, 5 * time.Second}) 809 require.NoError(t, err) 810 811 opts := testOptions().SetMessageRetryNanosFn(fn) 812 w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl) 813 814 m := newMessage() 815 m.IncWriteTimes() 816 retryAtNanos := w.nextRetryAfterNanos(m.WriteTimes()) 817 require.Equal(t, int64(time.Minute), retryAtNanos) 818 819 m.IncWriteTimes() 820 retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes()) 821 require.Equal(t, int64(10*time.Second), retryAtNanos) 822 823 m.IncWriteTimes() 824 retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes()) 825 require.Equal(t, int64(5*time.Second), retryAtNanos) 826 827 m.IncWriteTimes() 828 retryAtNanos = w.nextRetryAfterNanos(m.WriteTimes()) 829 require.Equal(t, int64(5*time.Second), retryAtNanos) 830 } 831 832 func TestExpectedProcessedAt(t *testing.T) { 833 m := newMessage() 834 m.initNanos = 100 835 m.SetRetryAtNanos(200) 836 require.Equal(t, int64(100), m.ExpectedProcessAtNanos()) 837 m.SetRetryAtNanos(300) 838 require.Equal(t, int64(200), m.ExpectedProcessAtNanos()) 839 } 840 841 func TestMessageWriterCloseCleanupAllMessages(t *testing.T) { 842 defer leaktest.Check(t)() 843 844 opts := testOptions() 845 w := newMessageWriter(200, nil, opts, testMessageWriterMetrics()).(*messageWriterImpl) 846 847 ctrl := xtest.NewController(t) 848 defer ctrl.Finish() 849 850 mm := producer.NewMockMessage(ctrl) 851 mm.EXPECT().Size().Return(3) 852 853 rm := producer.NewRefCountedMessage(mm, nil) 854 mm.EXPECT().Finalize(producer.Consumed) 855 mm.EXPECT().Bytes().Return([]byte("foo")) 856 w.Write(rm) 857 require.False(t, isEmptyWithLock(w.acks)) 858 require.Equal(t, 1, w.queue.Len()) 859 w.Init() 860 w.Close() 861 require.Equal(t, 0, w.queue.Len()) 862 require.True(t, isEmptyWithLock(w.acks)) 863 } 864 865 func TestMessageWriterQueueFullScanOnWriteErrors(t *testing.T) { 866 ctrl := xtest.NewController(t) 867 defer ctrl.Finish() 868 869 opts := testOptions().SetMessageQueueScanBatchSize(1) 870 scope := tally.NewTestScope("", nil) 871 metrics := testMessageWriterMetricsWithScope(scope).withConsumer("c1") 872 w := newMessageWriter(200, nil, opts, metrics).(*messageWriterImpl) 873 w.AddConsumerWriter(newConsumerWriter("bad", nil, opts, testConsumerWriterMetrics())) 874 875 mm1 := producer.NewMockMessage(ctrl) 876 mm1.EXPECT().Size().Return(3) 877 mm1.EXPECT().Bytes().Return([]byte("foo")) 878 rm1 := producer.NewRefCountedMessage(mm1, nil) 879 w.Write(rm1) 880 require.Equal(t, 1, w.queue.Len()) 881 882 mm2 := producer.NewMockMessage(ctrl) 883 mm2.EXPECT().Size().Return(3) 884 mm2.EXPECT().Bytes().Return([]byte("foo")) 885 rm2 := producer.NewRefCountedMessage(mm2, nil) 886 w.Write(rm2) 887 require.Equal(t, 2, w.queue.Len()) 888 889 mm1.EXPECT().Finalize(producer.Dropped) 890 rm1.Drop() 891 w.scanMessageQueue() 892 require.Equal(t, 1, w.queue.Len()) 893 894 snapshot := scope.Snapshot() 895 counters := snapshot.Counters() 896 require.Equal(t, int64(1), counters["message-processed+consumer=c1,result=write"].Value()) 897 require.Equal(t, int64(1), counters["message-processed+consumer=c1,result=drop"].Value()) 898 } 899 900 func TestMessageWriter_WithoutConsumerScope(t *testing.T) { 901 ctrl := xtest.NewController(t) 902 defer ctrl.Finish() 903 904 opts := testOptions().SetMessageQueueScanBatchSize(1) 905 scope := tally.NewTestScope("", nil) 906 metrics := newMessageWriterMetrics(scope, instrument.TimerOptions{}, true) 907 w := newMessageWriter(200, nil, opts, metrics).(*messageWriterImpl) 908 w.AddConsumerWriter(newConsumerWriter("bad", nil, opts, testConsumerWriterMetrics())) 909 910 snapshot := scope.Snapshot() 911 counters := snapshot.Counters() 912 require.Nil(t, counters["message-processed+consumer=c1,result=write"]) 913 require.NotNil(t, counters["message-processed+result=write"]) 914 } 915 916 func isEmptyWithLock(h *acks) bool { 917 h.Lock() 918 defer h.Unlock() 919 return len(h.ackMap) == 0 920 } 921 922 func testMessagePool(opts Options) messagePool { 923 p := newMessagePool(opts.MessagePoolOptions()) 924 p.Init() 925 return p 926 } 927 928 func testMessageWriterMetrics() messageWriterMetrics { 929 return newMessageWriterMetrics(tally.NoopScope, instrument.TimerOptions{}, false) 930 } 931 932 func testMessageWriterMetricsWithScope(scope tally.TestScope) messageWriterMetrics { 933 return newMessageWriterMetrics(scope, instrument.TimerOptions{}, false) 934 } 935 936 func validateMessages(t *testing.T, msgs []*producer.RefCountedMessage, w *messageWriterImpl) { 937 w.RLock() 938 idx := 0 939 for e := w.queue.Front(); e != nil; e = e.Next() { 940 require.Equal(t, msgs[idx].Bytes(), e.Value.(*message).RefCountedMessage.Bytes()) 941 idx++ 942 } 943 w.RUnlock() 944 require.Equal(t, idx, len(msgs)) 945 }