Skip to content

Add expiration for stored request durations #193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions src/Stats.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ namespace SpacetimeDB
{
public class NetworkRequestTracker
{
private readonly ConcurrentQueue<(DateTime End, TimeSpan Duration, string Metadata)> _requestDurations = new();
private readonly ConcurrentQueue<(DateTime End, (TimeSpan Duration, string Metadata) Request)> _requestDurations = new();

private uint _nextRequestId;
private readonly Dictionary<uint, (DateTime Start, string Metadata)> _requests = new();

// Limit the number of request durations we store to prevent memory leaks.
public int KeepLastSeconds = 5 * 60;

internal uint StartTrackingRequest(string metadata = "")
{
// Record the start time of the request
Expand Down Expand Up @@ -40,9 +43,25 @@ internal bool FinishTrackingRequest(uint requestId)
return true;
}

private IEnumerable<(TimeSpan Duration, string Metadata)> GetRequestDurations(int lastSeconds)
{
var cutoff = DateTime.UtcNow.AddSeconds(-lastSeconds);
return _requestDurations.SkipWhile(x => x.End < cutoff).Select(x => x.Request);
}

internal void InsertRequest(TimeSpan duration, string metadata)
{
_requestDurations.Enqueue((DateTime.UtcNow, duration, metadata));
lock (_requestDurations)
{
// Remove expired entries, we need to do this atomically.
var cutoff = DateTime.UtcNow.AddSeconds(-KeepLastSeconds);
var removeCount = _requestDurations.TakeWhile(x => x.End < cutoff).Count();
for (var i = 0; i < removeCount; i++)
{
_requestDurations.TryDequeue(out _);
}
_requestDurations.Enqueue((DateTime.UtcNow, (duration, metadata)));
}
}

internal void InsertRequest(DateTime start, string metadata)
Expand All @@ -52,8 +71,13 @@ internal void InsertRequest(DateTime start, string metadata)

public ((TimeSpan Duration, string Metadata) Min, (TimeSpan Duration, string Metadata) Max)? GetMinMaxTimes(int lastSeconds)
{
if (lastSeconds > KeepLastSeconds)
{
throw new ArgumentException($"lastSeconds must be less than or equal to KeepLastSeconds = {KeepLastSeconds}", nameof(lastSeconds));
}

var cutoff = DateTime.UtcNow.AddSeconds(-lastSeconds);
var requestDurations = _requestDurations.Where(x => x.End >= cutoff).Select(x => (x.Duration, x.Metadata));
var requestDurations = _requestDurations.SkipWhile(x => x.End < cutoff).Select(x => x.Request);

if (!requestDurations.Any())
{
Expand All @@ -74,5 +98,14 @@ public class Stats
public readonly NetworkRequestTracker SubscriptionRequestTracker = new();
public readonly NetworkRequestTracker AllReducersTracker = new();
public readonly NetworkRequestTracker ParseMessageTracker = new();

public void KeepLastSeconds(int seconds)
{
ReducerRequestTracker.KeepLastSeconds = seconds;
OneOffRequestTracker.KeepLastSeconds = seconds;
SubscriptionRequestTracker.KeepLastSeconds = seconds;
AllReducersTracker.KeepLastSeconds = seconds;
ParseMessageTracker.KeepLastSeconds = seconds;
}
}
}
2 changes: 1 addition & 1 deletion tests~/VerifyInit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public override void Write(VerifyJsonWriter writer, NetworkRequestTracker value)
}

if (
value.GetMinMaxTimes(int.MaxValue) is
value.GetMinMaxTimes(60) is
{ Min.Metadata: var Min, Max.Metadata: var Max }
)
{
Expand Down
Loading