Skip to content

Commit

Permalink
Ensure realm subscriptions always fire initial callback with null `Ch…
Browse files Browse the repository at this point in the history
…angeSet`

We expect this to be the case, but it turns out that it [may be
coalesced](https://www.mongodb.com/docs/realm-sdks/dotnet/latest/reference/Realms.IRealmCollection-1.html#Realms_IRealmCollection_1_SubscribeForNotifications_Realms_NotificationCallbackDelegate__0__Realms_KeyPathsCollection_):

> Notifications are delivered via the standard event loop, and so can't
> be delivered while the event loop is blocked by other activity. When
> notifications can't be delivered instantly, multiple notifications may
> be coalesced into a single notification. This can include the
> notification with the initial collection.

Rather than struggle with handling this locally every time, let's fix
the callback at our end to ensure we receive the initial null case.

I've raised concern for the API being a bit silly with realm
(realm/realm-dotnet#3641).
  • Loading branch information
peppy committed Jul 9, 2024
1 parent c8b9c11 commit 2423bbb
Showing 1 changed file with 17 additions and 2 deletions.
19 changes: 17 additions & 2 deletions osu.Game/Database/RealmObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public static class RealmObjectExtensions
if (!d.Beatmaps.Contains(existingBeatmap))
{
Debug.Fail("Beatmaps should never become detached under normal circumstances. If this ever triggers, it should be investigated further.");
Logger.Log("WARNING: One of the difficulties in a beatmap was detached from its set. Please save a copy of logs and report this to devs.", LoggingTarget.Database, LogLevel.Important);
Logger.Log("WARNING: One of the difficulties in a beatmap was detached from its set. Please save a copy of logs and report this to devs.", LoggingTarget.Database,
LogLevel.Important);
d.Beatmaps.Add(existingBeatmap);
}

Expand Down Expand Up @@ -291,7 +292,21 @@ public static IDisposable QueryAsyncWithNotifications<T>(this IRealmCollection<T
if (!RealmAccess.CurrentThreadSubscriptionsAllowed)
throw new InvalidOperationException($"Make sure to call {nameof(RealmAccess)}.{nameof(RealmAccess.RegisterForNotifications)}");

return collection.SubscribeForNotifications(callback);
bool initial = true;
return collection.SubscribeForNotifications(((sender, changes) =>
{
if (initial)
{
initial = false;

// Realm might coalesce the initial callback, meaning we never receive a `ChangeSet` of `null` marking the first callback.
// Let's decouple it for simplicity in handling.
if (changes != null)
callback(sender, null);
}

callback(sender, changes);
}));
}

/// <summary>
Expand Down

0 comments on commit 2423bbb

Please sign in to comment.