-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6fc4550
commit 7da197e
Showing
8 changed files
with
902 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
namespace DotPulsar.Internal.Abstractions | ||
{ | ||
using System.Threading.Tasks; | ||
public interface IMessageQueue | ||
using System; | ||
|
||
public interface IMessageQueue : IDequeue<MessagePackage>, IDisposable | ||
{ | ||
MessageId Acknowledge(MessageId obj); | ||
MessageId NegativeAcknowledge(MessageId obj); | ||
void Acknowledge(MessageId obj); | ||
void NegativeAcknowledge(MessageId obj); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/DotPulsar/Internal/Abstractions/IUnackedMessageTracker.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
namespace DotPulsar.Internal.Abstractions | ||
{ | ||
using DotPulsar.Abstractions; | ||
using System.Threading.Tasks; | ||
using System; | ||
|
||
public interface IUnackedMessageTracker : IDisposable | ||
{ | ||
void Add(MessageId messageId); | ||
|
||
void Ack(MessageId messageId); | ||
|
||
Task Start(IConsumer consumer); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
namespace DotPulsar.Internal | ||
{ | ||
using System.Threading.Tasks; | ||
using Abstractions; | ||
using DotPulsar.Abstractions; | ||
|
||
public class InactiveUnackedMessageTracker : IUnackedMessageTracker | ||
{ | ||
public InactiveUnackedMessageTracker() | ||
{ | ||
} | ||
|
||
public void Ack(MessageId messageId) | ||
{ | ||
return; | ||
} | ||
|
||
public void Add(MessageId messageId) | ||
{ | ||
return; | ||
} | ||
|
||
public Task Start(IConsumer consumer) => Task.CompletedTask; | ||
|
||
public void Dispose() { | ||
return; | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
namespace DotPulsar.Internal | ||
{ | ||
using Abstractions; | ||
using DotPulsar.Abstractions; | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
public readonly struct AwaitingAck | ||
{ | ||
public MessageId MessageId { get; } | ||
public long Timestamp { get; } | ||
|
||
public AwaitingAck(MessageId messageId) | ||
{ | ||
MessageId = messageId; | ||
Timestamp = Stopwatch.GetTimestamp(); | ||
} | ||
|
||
public TimeSpan Elapsed => | ||
TimeSpan.FromTicks( | ||
(Stopwatch.GetTimestamp() - Timestamp) / | ||
(Stopwatch.Frequency) * 1000); | ||
} | ||
|
||
public sealed class UnackedMessageTracker : IUnackedMessageTracker | ||
{ | ||
private readonly TimeSpan _ackTimeout; | ||
private readonly TimeSpan _pollingTimeout; | ||
private readonly ConcurrentQueue<AwaitingAck> _awaitingAcks; | ||
private readonly List<MessageId> _acked; | ||
private readonly CancellationTokenSource _cancellationTokenSource; | ||
|
||
|
||
public UnackedMessageTracker(TimeSpan ackTimeout, TimeSpan pollingTimeout) | ||
{ | ||
_ackTimeout = ackTimeout; | ||
_pollingTimeout = pollingTimeout; | ||
_awaitingAcks = new ConcurrentQueue<AwaitingAck>(); | ||
_acked = new List<MessageId>(); | ||
_cancellationTokenSource = new CancellationTokenSource(); | ||
} | ||
|
||
public void Add(MessageId messageId) | ||
{ | ||
_awaitingAcks.Enqueue(new AwaitingAck(messageId)); | ||
} | ||
|
||
public void Ack(MessageId messageId) | ||
{ | ||
// We only need to store the highest cumulative ack we see (if there is one) | ||
// and the MessageIds not included by that cumulative ack. | ||
_acked.Add(messageId); | ||
} | ||
|
||
public Task Start(IConsumer consumer) | ||
{ | ||
var cancellationToken = _cancellationTokenSource.Token; | ||
|
||
return Task.Run(async () => { | ||
while (!cancellationToken.IsCancellationRequested) | ||
{ | ||
var messages = CheckUnackedMessages(); | ||
|
||
if (messages.Count() > 0) | ||
await consumer.RedeliverUnacknowledgedMessages(messages, cancellationToken); | ||
|
||
await Task.Delay(_pollingTimeout, cancellationToken); | ||
} | ||
}, cancellationToken); | ||
} | ||
|
||
private IEnumerable<MessageId> CheckUnackedMessages() | ||
{ | ||
AwaitingAck awaiting; | ||
var result = new List<MessageId>(); | ||
|
||
while (_awaitingAcks.TryPeek(out awaiting) | ||
&& awaiting.Elapsed > _ackTimeout) | ||
{ | ||
// Can I safely use Dequeue now instead of TryDequeue? | ||
if (_awaitingAcks.TryDequeue(out awaiting)) | ||
{ | ||
//If the MessageId is not acknowledged | ||
if (!_acked.Contains(awaiting.MessageId)) | ||
result.Add(awaiting.MessageId); | ||
else | ||
_acked.Remove(awaiting.MessageId); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
this._cancellationTokenSource.Cancel(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.