Skip to content

Commit 4d9a79d

Browse files
refactor(audience): return Task from DeleteData (SDK-147)
DeleteData fires a backend DELETE for GDPR erasure but returned void, so callers had no handle to know when the erasure completed or failed. FlushAsync returns Task for the same reason - symmetrising the lifecycle methods on the singleton. - Public signature becomes `public static Task DeleteData(string userId = null)`. - All early-return paths (not initialised, no config, no anonymousId) return Task.CompletedTask. - The hot path's Task.Run is just returned directly instead of discarded. No change to the actual HTTP request, error surfacing, or anonymousId-file-side-effect-avoidance contract. - Callers that want fire-and-forget still get it by ignoring the return value; callers that want to gate on completion can now await. Existing void-discarding call sites continue to compile. Two new tests: awaited task completes after DELETE dispatch, and the pre-Init guard returns Task.CompletedTask. 158 passing. Linear: SDK-147 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 47f9605 commit 4d9a79d

2 files changed

Lines changed: 38 additions & 6 deletions

File tree

src/Packages/Audience/Runtime/ImmutableAudience.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,16 @@ public static void Reset()
228228
Identity.Reset(config.PersistentDataPath);
229229
}
230230

231-
// Ask the backend to erase this player's data.
232-
public static void DeleteData(string userId = null)
231+
// Ask the backend to erase this player's data. Returns a task the
232+
// caller can await to know when the request is acknowledged, or
233+
// discard for fire-and-forget.
234+
public static Task DeleteData(string userId = null)
233235
{
234-
if (!_initialized) return;
236+
if (!_initialized) return Task.CompletedTask;
235237

236238
var config = _config;
237239
var client = _controlClient;
238-
if (config == null || client == null) return;
240+
if (config == null || client == null) return Task.CompletedTask;
239241

240242
string query;
241243
if (!string.IsNullOrEmpty(userId))
@@ -247,15 +249,15 @@ public static void DeleteData(string userId = null)
247249
// Get, not GetOrCreate — a brand-new install must not register an ID just to delete it.
248250
var anonymousId = Identity.Get(config.PersistentDataPath);
249251
if (string.IsNullOrEmpty(anonymousId))
250-
return;
252+
return Task.CompletedTask;
251253
query = "anonymousId=" + Uri.EscapeDataString(anonymousId);
252254
}
253255

254256
var url = Constants.DataUrl(config.PublishableKey) + "?" + query;
255257
var onError = config.OnError;
256258
var publishableKey = config.PublishableKey;
257259

258-
Task.Run(async () =>
260+
return Task.Run(async () =>
259261
{
260262
try
261263
{

src/Packages/Audience/Tests/Runtime/DeleteDataTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Linq;
45
using System.Net;
56
using System.Net.Http;
67
using System.Threading;
@@ -144,6 +145,35 @@ public void DeleteData_DoesNotCreateAnonymousIdFile()
144145
"DeleteData must not create the anonymousId file as a side effect");
145146
}
146147

148+
[Test]
149+
public async Task DeleteData_ReturnsTask_ThatCompletesAfterRequest()
150+
{
151+
var handler = new CapturingHandler();
152+
ImmutableAudience.Init(MakeConfig(handler));
153+
154+
var task = ImmutableAudience.DeleteData(userId: "player-42");
155+
Assert.IsNotNull(task, "DeleteData must return a non-null Task");
156+
157+
// Await directly: no need for the RequestSent gate when the task
158+
// already represents completion.
159+
await task;
160+
161+
Assert.IsTrue(handler.Requests.Any(r => r.Method == HttpMethod.Delete),
162+
"DELETE request must have been sent by the time the task completes");
163+
}
164+
165+
[Test]
166+
public void DeleteData_BeforeInit_ReturnsCompletedTask()
167+
{
168+
// Not initialised — must not throw, must return a completed Task.
169+
ImmutableAudience.ResetState();
170+
171+
var task = ImmutableAudience.DeleteData(userId: "player-42");
172+
173+
Assert.IsNotNull(task);
174+
Assert.IsTrue(task.IsCompleted, "DeleteData before Init must return an already-completed Task");
175+
}
176+
147177
[Test]
148178
public void DeleteData_ServerError_InvokesOnError()
149179
{

0 commit comments

Comments
 (0)