|
1 | 1 | using System.Collections.Concurrent;
|
| 2 | +using System.Diagnostics; |
2 | 3 | using System.Net;
|
3 | 4 | using System.Security.Authentication;
|
4 | 5 | using MySqlConnector.Logging;
|
@@ -551,27 +552,50 @@ private ConnectionPool(ConnectionSettings cs)
|
551 | 552 |
|
552 | 553 | private void StartReaperTask()
|
553 | 554 | {
|
554 |
| - if (ConnectionSettings.ConnectionIdleTimeout > 0) |
| 555 | + if (ConnectionSettings.ConnectionIdleTimeout <= 0) |
| 556 | + return; |
| 557 | + |
| 558 | + var reaperInterval = TimeSpan.FromSeconds(Math.Max(1, Math.Min(60, ConnectionSettings.ConnectionIdleTimeout / 2))); |
| 559 | + |
| 560 | +#if NET6_0_OR_GREATER |
| 561 | + m_reaperTimer = new PeriodicTimer(reaperInterval); |
| 562 | + _ = RunTimer(); |
| 563 | + |
| 564 | + async Task RunTimer() |
555 | 565 | {
|
556 |
| - var reaperInterval = TimeSpan.FromSeconds(Math.Max(1, Math.Min(60, ConnectionSettings.ConnectionIdleTimeout / 2))); |
557 |
| - m_reaperTask = Task.Run(async () => |
| 566 | + while (await m_reaperTimer.WaitForNextTickAsync().ConfigureAwait(false)) |
558 | 567 | {
|
559 |
| - while (true) |
| 568 | + try |
560 | 569 | {
|
561 |
| - var task = Task.Delay(reaperInterval); |
562 |
| - try |
563 |
| - { |
564 |
| - using var source = new CancellationTokenSource(reaperInterval); |
565 |
| - await ReapAsync(IOBehavior.Asynchronous, source.Token).ConfigureAwait(false); |
566 |
| - } |
567 |
| - catch |
568 |
| - { |
569 |
| - // do nothing; we'll try to reap again |
570 |
| - } |
571 |
| - await task.ConfigureAwait(false); |
| 570 | + using var source = new CancellationTokenSource(reaperInterval); |
| 571 | + await ReapAsync(IOBehavior.Asynchronous, source.Token).ConfigureAwait(false); |
572 | 572 | }
|
573 |
| - }); |
| 573 | + catch |
| 574 | + { |
| 575 | + // do nothing; we'll try to reap again |
| 576 | + } |
| 577 | + } |
574 | 578 | }
|
| 579 | +#else |
| 580 | + m_reaperTimer = new Timer(t => |
| 581 | + { |
| 582 | + var stopwatch = Stopwatch.StartNew(); |
| 583 | + try |
| 584 | + { |
| 585 | + using var source = new CancellationTokenSource(reaperInterval); |
| 586 | + ReapAsync(IOBehavior.Synchronous, source.Token).GetAwaiter().GetResult(); |
| 587 | + } |
| 588 | + catch |
| 589 | + { |
| 590 | + // do nothing; we'll try to reap again |
| 591 | + } |
| 592 | + |
| 593 | + // restart the timer, accounting for the time spent reaping |
| 594 | + var delay = reaperInterval - stopwatch.Elapsed; |
| 595 | + ((Timer) t!).Change(delay < TimeSpan.Zero ? TimeSpan.Zero : delay, TimeSpan.FromMilliseconds(-1)); |
| 596 | + }); |
| 597 | + m_reaperTimer.Change(reaperInterval, TimeSpan.FromMilliseconds(-1)); |
| 598 | +#endif |
575 | 599 | }
|
576 | 600 |
|
577 | 601 | private void StartDnsCheckTimer()
|
@@ -717,13 +741,14 @@ private static void OnAppDomainShutDown(object? sender, EventArgs e) =>
|
717 | 741 | private readonly Dictionary<string, int>? m_hostSessions;
|
718 | 742 | private readonly object[] m_logArguments;
|
719 | 743 | private int m_generation;
|
720 |
| - private Task? m_reaperTask; |
721 | 744 | private uint m_lastRecoveryTime;
|
722 | 745 | private int m_lastSessionId;
|
723 | 746 | private Dictionary<string, CachedProcedure?>? m_procedureCache;
|
724 | 747 | #if NET6_0_OR_GREATER
|
725 | 748 | private PeriodicTimer? m_dnsCheckTimer;
|
| 749 | + private PeriodicTimer? m_reaperTimer; |
726 | 750 | #else
|
727 | 751 | private Timer? m_dnsCheckTimer;
|
| 752 | + private Timer? m_reaperTimer; |
728 | 753 | #endif
|
729 | 754 | }
|
0 commit comments