Skip to content

Commit 168a521

Browse files
thekeys93Zeki Sherif
authored andcommitted
appender: fix races in tracing-appender unit tests (tokio-rs#737)
## Motivation I was able to reproduce the failures for `logs_dropped_if_lossy` on my machine when using loom. Realized that the Worker calls `recv` and the only time we actually will increment the error_counter is when we have a write blocking on the call to `write_all` (called by the worker) and a messege buffered in NonBlocking crossbeam sender. ## Solution I added some sleeps after writes to avoid some races I saw. For `multi_threaded_writes`, what likely is happening is that sometimes the last thread hasn't had a chance write to the queue, hence we now use `recv_timeout` instead of `try_recv`, to ensure there's more than enough time for the message to be visible in the channel. Co-authored-by: Zeki Sherif <[email protected]>
1 parent 5f6e35b commit 168a521

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

tracing-appender/src/non_blocking.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,13 @@ mod test {
333333
assert_eq!(line, ", World");
334334
}
335335

336+
fn write_non_blocking(non_blocking: &mut NonBlocking, msg: &[u8]) {
337+
non_blocking.write_all(msg).expect("Failed to write");
338+
339+
// Sleep a bit to prevent races.
340+
thread::sleep(Duration::from_millis(200));
341+
}
342+
336343
#[test]
337344
fn logs_dropped_if_lossy() {
338345
let (mock_writer, rx) = MockWriter::new(1);
@@ -344,27 +351,34 @@ mod test {
344351

345352
let error_count = non_blocking.error_counter();
346353

347-
non_blocking.write_all(b"Hello").expect("Failed to write");
354+
// First write will not block
355+
write_non_blocking(&mut non_blocking, b"Hello");
348356
assert_eq!(0, error_count.load(Ordering::Acquire));
349357

350-
non_blocking.write_all(b", World").expect("Failed to write");
351-
assert_eq!(1, error_count.load(Ordering::Acquire));
358+
// Second write will not block as Worker will have called `recv` on channel.
359+
// "Hello" is not yet consumed. MockWriter call to write_all will block until
360+
// "Hello" is consumed.
361+
write_non_blocking(&mut non_blocking, b", World");
362+
assert_eq!(0, error_count.load(Ordering::Acquire));
352363

353-
non_blocking.write_all(b".").expect("Failed to write");
354-
assert_eq!(2, error_count.load(Ordering::Acquire));
364+
// Will sit in NonBlocking channel's buffer.
365+
write_non_blocking(&mut non_blocking, b"Test");
366+
assert_eq!(0, error_count.load(Ordering::Acquire));
355367

356-
// Allow a line to be written
368+
// Allow a line to be written. "Hello" message will be consumed.
369+
// ", World" will be able to write to MockWriter.
370+
// "Test" will block on call to MockWriter's `write_all`
357371
let line = rx.recv().unwrap();
358372
assert_eq!(line, "Hello");
359373

360-
// Now, there is once again capacity in the buffer.
361-
non_blocking
362-
.write_all(b"Universe")
363-
.expect("Failed to write");
364-
assert_eq!(2, error_count.load(Ordering::Acquire));
374+
// This will block as NonBlocking channel is full.
375+
write_non_blocking(&mut non_blocking, b"Universe");
376+
assert_eq!(1, error_count.load(Ordering::Acquire));
365377

378+
// Finally the second message sent will be consumed.
366379
let line = rx.recv().unwrap();
367-
assert_eq!(line, "Universe");
380+
assert_eq!(line, ", World");
381+
assert_eq!(1, error_count.load(Ordering::Acquire));
368382
}
369383

370384
#[test]
@@ -394,7 +408,7 @@ mod test {
394408

395409
let mut hello_count: u8 = 0;
396410

397-
while let Ok(event_str) = rx.try_recv() {
411+
while let Ok(event_str) = rx.recv_timeout(Duration::from_secs(5)) {
398412
assert!(event_str.contains("Hello"));
399413
hello_count += 1;
400414
}

0 commit comments

Comments
 (0)