Skip to content

Commit 1d1a56d

Browse files
refactor(audience-sdk): consolidate timing/retry constants in Constants.cs
The previous SSOT pass left twelve timing / retry constants co-located with their owning module: HttpTransport.RequestTimeoutSeconds and five Backoff*Ms constants, Session.HeartbeatIntervalMs / PauseTimeoutMs / HeartbeatDrainTimeoutMs / StartDrainTimeoutMs, and ImmutableAudience. ConsentSyncMaxAttempts / ConsentSyncBaseRetryMs. Constants.cs already held analogous timing / sizing knobs (DefaultFlushIntervalSeconds, MaxBatchSize, ControlPlaneRequestTimeoutSeconds), so the split was inconsistent. Move all twelve into Constants.cs with module-prefixed names (MessagesRequestTimeoutSeconds, HttpBackoff{1st,2nd,3rd,4th,Cap}Ms, SessionHeartbeatIntervalMs, SessionPauseTimeoutMs, SessionHeartbeatDrainTimeoutMs, SessionStartDrainTimeoutMs, ConsentSyncMaxAttempts, ConsentSyncBaseRetryMs). Migrate runtime call sites in HttpTransport, Session, and ImmutableAudience plus the one test reference in SessionTests. Behaviour unchanged. Follow-up to SDK-272 (centralisation of duplicated literals).
1 parent ec1c9e0 commit 1d1a56d

5 files changed

Lines changed: 46 additions & 47 deletions

File tree

src/Packages/Audience/Runtime/Core/Constants.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,35 @@ internal static class Constants
2525
internal const string RoundTripNumberFormat = "R";
2626
internal const int ControlPlaneRequestTimeoutSeconds = 30;
2727

28+
// How long we wait for one POST before giving up.
29+
// Without this, one stuck request can block everything else.
30+
internal const int MessagesRequestTimeoutSeconds = 30;
31+
32+
// How long we wait before retrying after a failed POST. Doubles each time.
33+
internal const int HttpBackoff1stMs = 5_000;
34+
internal const int HttpBackoff2ndMs = 10_000;
35+
internal const int HttpBackoff3rdMs = 20_000;
36+
internal const int HttpBackoff4thMs = 40_000;
37+
internal const int HttpBackoffCapMs = 60_000;
38+
39+
// How often a session_heartbeat is emitted while a session is live.
40+
internal const int SessionHeartbeatIntervalMs = 60_000;
41+
42+
// How long a paused session can stay paused before Resume rolls it.
43+
internal const int SessionPauseTimeoutMs = 30_000;
44+
45+
// How long we wait for an in-flight heartbeat callback to finish during teardown.
46+
internal const int SessionHeartbeatDrainTimeoutMs = 1_000;
47+
48+
// How long we wait for the previous heartbeat to clear when Start is called twice.
49+
internal const int SessionStartDrainTimeoutMs = 500;
50+
51+
// How many times we retry the consent-sync PUT after a 429.
52+
internal const int ConsentSyncMaxAttempts = 4;
53+
54+
// How long we wait before the first consent-sync retry. Doubles each time.
55+
internal const int ConsentSyncBaseRetryMs = 1_000;
56+
2857
internal const string LibraryName = "com.immutable.audience";
2958
internal const string LibraryVersion = "0.1.0";
3059
internal const string Surface = "unity";

src/Packages/Audience/Runtime/Core/Session.cs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,6 @@ namespace Immutable.Audience
2323
// any thread.
2424
internal sealed class Session : IDisposable
2525
{
26-
internal const int HeartbeatIntervalMs = 60_000;
27-
28-
// 30s: alt-tab beyond this rolls the session on Resume.
29-
internal const int PauseTimeoutMs = 30_000;
30-
31-
// How long we wait for an in-flight heartbeat callback to finish during teardown.
32-
internal const int HeartbeatDrainTimeoutMs = 1_000;
33-
34-
// How long we wait for the previous heartbeat to clear when Start is called twice.
35-
internal const int StartDrainTimeoutMs = 500;
36-
3726
private readonly TrackDelegate _track;
3827
private readonly Func<DateTime> _getUtcNow;
3928
private readonly int _heartbeatIntervalMs;
@@ -57,7 +46,7 @@ internal string? SessionId
5746
internal Session(
5847
TrackDelegate track,
5948
Func<DateTime>? getUtcNow = null,
60-
int heartbeatIntervalMs = HeartbeatIntervalMs)
49+
int heartbeatIntervalMs = Constants.SessionHeartbeatIntervalMs)
6150
{
6251
_track = track ?? throw new ArgumentNullException(nameof(track));
6352
_getUtcNow = getUtcNow ?? (() => DateTime.UtcNow);
@@ -83,8 +72,8 @@ internal void Start()
8372
}
8473
}
8574

86-
// Double-Start is a misuse path; StartDrainTimeoutMs caps the wait.
87-
TimerDisposal.DisposeAndWait(oldTimer, TimeSpan.FromMilliseconds(StartDrainTimeoutMs));
75+
// Cap the wait so a misuse Start-twice path doesn't hang.
76+
TimerDisposal.DisposeAndWait(oldTimer, TimeSpan.FromMilliseconds(Constants.SessionStartDrainTimeoutMs));
8877

8978
// Phase 2: populate new state. Re-check _disposed (may have flipped during drain).
9079
string sessionId;
@@ -139,7 +128,7 @@ internal void Resume()
139128
// Clamp: wall-clock rewind (NTP) would otherwise over-credit engagement.
140129
if (pauseDuration < TimeSpan.Zero) pauseDuration = TimeSpan.Zero;
141130

142-
extended = pauseDuration.TotalMilliseconds > PauseTimeoutMs;
131+
extended = pauseDuration.TotalMilliseconds > Constants.SessionPauseTimeoutMs;
143132

144133
// Credit in both paths. End (and then Start) reset the accumulator
145134
// on the extended-pause rollover so there is no double-count.
@@ -270,8 +259,7 @@ private void SafeTrack(string eventName, Dictionary<string, object> properties)
270259
}
271260

272261
// Stops the timer and waits for the in-flight callback. Runs outside
273-
// _lock (OnHeartbeat re-enters). HeartbeatDrainTimeoutMs caps the
274-
// wait so quits don't hang. Warns on timeout.
262+
// Cap the wait so quits don't hang on a re-entrant heartbeat.
275263
private void DrainHeartbeatTimer()
276264
{
277265
Timer? timer;
@@ -282,7 +270,7 @@ private void DrainHeartbeatTimer()
282270
}
283271
if (timer == null) return;
284272

285-
if (!TimerDisposal.DisposeAndWait(timer, TimeSpan.FromMilliseconds(HeartbeatDrainTimeoutMs)))
273+
if (!TimerDisposal.DisposeAndWait(timer, TimeSpan.FromMilliseconds(Constants.SessionHeartbeatDrainTimeoutMs)))
286274
{
287275
Log.Warn(AudienceLogs.SessionHeartbeatTimeout);
288276
}

src/Packages/Audience/Runtime/ImmutableAudience.cs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ public static class ImmutableAudience
2727
// teardown (Session.Dispose, timer drain, queue shutdown, transport
2828
// flush, disposes). This keeps the hold time to nanoseconds so a caller
2929
// arriving on a different thread is not stranded behind those budgets.
30-
// How many times we retry the consent-sync PUT after a 429.
31-
internal const int ConsentSyncMaxAttempts = 4;
32-
33-
// How long we wait before the first consent-sync retry. Doubles each time.
34-
internal const int ConsentSyncBaseRetryMs = 1_000;
35-
3630
private static AudienceConfig? _config;
3731
private static DiskStore? _store;
3832
private static EventQueue? _queue;
@@ -631,9 +625,8 @@ private static void SyncConsentToBackend(AudienceConfig config, ConsentLevel lev
631625

632626
Task.Run(async () =>
633627
{
634-
// 429 retried up to ConsentSyncMaxAttempts attempts (1s/2s/4s
635-
// or Retry-After). Other non-2xx fail fast.
636-
const int maxAttempts = ConsentSyncMaxAttempts;
628+
// 429 retries up to Constants.ConsentSyncMaxAttempts; other non-2xx fail fast.
629+
const int maxAttempts = Constants.ConsentSyncMaxAttempts;
637630
var attempt = 0;
638631
try
639632
{
@@ -650,7 +643,7 @@ private static void SyncConsentToBackend(AudienceConfig config, ConsentLevel lev
650643
if (response.StatusCode == HttpStatusCode.TooManyRequests && attempt < maxAttempts)
651644
{
652645
var delay = HttpRetry.ParseRetryAfter(response)
653-
?? TimeSpan.FromMilliseconds(ConsentSyncBaseRetryMs * (1 << (attempt - 1)));
646+
?? TimeSpan.FromMilliseconds(Constants.ConsentSyncBaseRetryMs * (1 << (attempt - 1)));
654647
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
655648
continue;
656649
}

src/Packages/Audience/Runtime/Transport/HttpTransport.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,6 @@ namespace Immutable.Audience
1515
// Sends queued events from DiskStore to the Audience backend.
1616
internal sealed class HttpTransport : IDisposable
1717
{
18-
// How long we wait for one POST before giving up.
19-
// Without this, one stuck request can block everything else.
20-
internal const int RequestTimeoutSeconds = 30;
21-
22-
// How long we wait before retrying after a failed POST. Doubles each time.
23-
internal const int Backoff1stMs = 5_000;
24-
internal const int Backoff2ndMs = 10_000;
25-
internal const int Backoff3rdMs = 20_000;
26-
internal const int Backoff4thMs = 40_000;
27-
internal const int BackoffCapMs = 60_000;
28-
2918
private readonly DiskStore _store;
3019
private readonly string _url;
3120
private readonly string _publishableKey;
@@ -59,7 +48,7 @@ internal HttpTransport(
5948
_client = handler != null
6049
? new HttpClient(handler, disposeHandler: false)
6150
: new HttpClient();
62-
_client.Timeout = TimeSpan.FromSeconds(RequestTimeoutSeconds);
51+
_client.Timeout = TimeSpan.FromSeconds(Constants.MessagesRequestTimeoutSeconds);
6352
_getUtcNow = getUtcNow ?? (() => DateTime.UtcNow);
6453
}
6554

@@ -193,11 +182,11 @@ internal int BackoffMs
193182
private int BackoffMsLocked() => _consecutiveFailures switch
194183
{
195184
<= 0 => 0,
196-
1 => Backoff1stMs,
197-
2 => Backoff2ndMs,
198-
3 => Backoff3rdMs,
199-
4 => Backoff4thMs,
200-
_ => BackoffCapMs,
185+
1 => Constants.HttpBackoff1stMs,
186+
2 => Constants.HttpBackoff2ndMs,
187+
3 => Constants.HttpBackoff3rdMs,
188+
4 => Constants.HttpBackoff4thMs,
189+
_ => Constants.HttpBackoffCapMs,
201190
};
202191

203192
// Earliest UTC time at which the next attempt may run.

src/Packages/Audience/Tests/Runtime/Core/SessionTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ public void Pause_ThenResume_LongPause_StartsNewSession()
158158
var id1 = session.SessionId;
159159

160160
session.Pause();
161-
now = now.AddMilliseconds(Session.PauseTimeoutMs + 1000);
161+
now = now.AddMilliseconds(Constants.SessionPauseTimeoutMs + 1000);
162162
session.Resume();
163163

164164
Assert.AreNotEqual(id1, session.SessionId,
165-
"pause longer than PauseTimeoutMs should end the old session and start a new one");
165+
"pause longer than SessionPauseTimeoutMs should end the old session and start a new one");
166166
Assert.IsTrue(_events.Any(e => e.name == EventNames.SessionEnd),
167167
"old session should have fired session_end");
168168
Assert.AreEqual(2, _events.Count(e => e.name == EventNames.SessionStart),

0 commit comments

Comments
 (0)