Data download on Initialization with FlexibleSyncConfiguration

I am developing .NET Maui app with MongoDB App Services and FlexibleSync. I am getting issue in the following code:

 FlexibleSyncConfiguration = new FlexibleSyncConfiguration(RealmUser)
                    {
                        PopulateInitialSubscriptions = (realm) =>
                        {
                            IQueryable<Player> player = realm.All<Player>().Where(n => n.OwnerId =RealmUser.Id);
                            IQueryable<AgeGroup> ageGroups = realm.All<AgeGroup>();
                            IQueryable<Game> games = realm.All<Game>();
                            realm.Subscriptions.Add(player);
                            realm.Subscriptions.Add(ageGroups);
                            realm.Subscriptions.Add(games);
                        }
                     };

Before the above subscriptions are added the below line is called and it does not return and the app hangs in there.

Realm realmInstance = await Realm.GetInstanceAsync(flexibleSyncConfiguration);

I am using this same code in App.cs and LoginViewModel becuase I need the data from MongoDB in both of these classes before deciding the next Page for Navigation.

The Models are:

  public class Player: RealmObject
    {
        [PrimaryKey]
        [MapTo("_id")]
        public ObjectId Id { get; set; } = ObjectId.GenerateNewId();

        [MapTo("owner_id")]
        public string OwnerId { get; set; }

        [MapTo("fullName")]
        public string FullName { get; set; }

        [MapTo("eMail")]
        public string Email { get; set; }

        [MapTo("country")]
        public string Country { get; set; } 

        [MapTo("mobileNumber")]
        public string MobileNumber { get; set; }

        [MapTo("province")]
        public string Province { get; set; }

        [MapTo("city")]
        public string City { get; set; }

        [MapTo("profileImage")]
        public byte[] ProfileImage { get; set; }   

        [MapTo("ageGroup")]
        public AgeGroup AgeGroup { get; set; }


        [MapTo("favouriteGames")]
        public IList<Game> FavouriteGames { get; }
    }
public class Game : RealmObject
    {
        [PrimaryKey]
        [MapTo("_id")]
        public ObjectId Id { get; set; } = ObjectId.GenerateNewId();

        [MapTo("name")]
        public string Name { get; set; }


    }
 public class AgeGroup: RealmObject
    {
        [PrimaryKey]
        [MapTo("_id")]
        public ObjectId Id { get; set; } = ObjectId.GenerateNewId();

        public string AgeGroupName { get; set; }
    }

Please not that the Game and AgeGroup are capped collections with just 5 to 6 documents which is read only and client does not write to these collections. My questions are:

  • What correction in this code will enable data download

  • Why the GetInstanceAsync does not return exception

  • How to set timeout on GetInstanceAsync()

GetInstanceAsync takes a cancellation token argument - you can use that to set a timeout (see this article for examples).

Regarding why GetInstanceAsync doesn’t throw an exception - it’s due to this bug - the original design of the API was assuming that eventually a connection will be established, so it’ll keep retrying the connection forever. We are now aware of certain conditions which will prevent sync from ever working (such as a schema mismatch), but haven’t gotten around to updating the API to communicate those errors.

Finally, I’m not sure why your code doesn’t work, but I’m guessing there’s an issue with the communication between the client and the server. This should be surfaced at least in the client logs, but also possibly in the server logs. Can you run your app and share the client logs from an attempted connection?

I believe there is some issue on Device Sync. When I disable sync, delete all schemas and try to re-enable the sync I get the following error:

permissions contain rule for table “AgeGroup” which does not exist in schema

Again clicking on Re-Enable Sync produce this error:

permissions contain rule for table “Game” which does not exist in schema

The permission json is as follows:

{
  "rules": {
    "AgeGroup": [
      {
        "name": "user",
        "applyWhen": {},
        "read": true,
        "write": false
      }
    ],
    "Game": [
      {
        "name": "user",
        "applyWhen": {},
        "read": true,
        "write": false
      }
    ]
  },
  "defaultRoles": [
    {
      "name": "admin",
      "applyWhen": {
        "%%user.custom_data.isGlobalAdmin": true
      },
      "read": true,
      "write": true
    },
    {
      "name": "user",
      "applyWhen": {},
      "read": {
        "owner_id": "%%user.id"
      },
      "write": {
        "owner_id": "%%user.id"
      }
    }
  ]
}

Sync is Enabled after generating schemas for the AgeGroup and Game Table from the Sample data. The original error still exists. You asked for the client logs. But I am not logging in the app. Can you please explain what info you want . The server logs sometimes show:

InitialSyncNotCompleted Error
Error:
attempted to start a session while initial sync is in progress (ProtocolErrorCode=229)

and sometimes

OK
Logs:
[
“Connection was active for: 1s”
]

Also this message at the top:

Enabling Sync …approximately 0/11 (0.00%) documents copied

I have 6 docs in Game and 5 docs in AgeGroup. Does the above message is about them

The Realm SDK will automatically log operations to the console. You can configure that to also log to a file if you’re not able to capture the console logs. Here’s the docs about it and the file logger would be something like:

Logger.Default = Logger.File("/usr/realm.log");

Make sure to call this before you create an App instance though.

This is the copy of the output window in Visual Studio. The connection is logged multiple times until cancelled by the Cancellation Token:

[DOTNET] 2023-01-12 13:57:14.441 Info: Connection[1]: Session[1]: client_reset_config = false, Realm exists = true, client reset = false
[DOTNET] 2023-01-12 13:57:14.898 Info: Connected to endpoint '3.210.32.164:443' (from '10.0.2.16:45886')
[EGL_emulation] app_time_stats: avg=1.95ms min=1.19ms max=4.43ms count=60
[DOTNET] 2023-01-12 13:57:15.313 Info: Verifying server SSL certificate using 155 root certificates
[EGL_emulation] app_time_stats: avg=1.83ms min=1.16ms max=3.88ms count=61
[DOTNET] 2023-01-12 13:57:16.492 Info: Connection[1]: Session[1]: Received: ERROR "Client tried to connect using flexible sync before initial sync is complete" (error_code=229, try_again=true, error_action=Transient)
[DOTNET] 2023-01-12 13:57:16.494 Info: Connection[1]: Disconnected
[EGL_emulation] app_time_stats: avg=1.88ms min=1.13ms max=3.98ms count=60
[JavaBinder] !!! FAILED BINDER TRANSACTION !!!  (parcel size = 316)
[GmsClient] IGmsServiceBroker.getService failed
[GmsClient] android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died, but this could also be caused by running out of binder buffe
[GmsClient] 	at android.os.BinderProxy.transactNative(Native Method)
[GmsClient] 	at android.os.BinderProxy.transact(BinderProxy.java:584)
[GmsClient] 	at com.google.android.gms.common.internal.zzac.getService(com.google.android.gms:play-services-basement@@18.1.0:8)
[GmsClient] 	at com.google.android.gms.common.internal.BaseGmsClient.getRemoteService(com.google.android.gms:play-services-basement@@18.1.0:14)
[GmsClient] 	at com.google.android.gms.common.api.internal.zabt.run(com.google.android.gms:play-services-base@@18.1.0:7)
[GmsClient] 	at android.os.Handler.handleCallback(Handler.java:942)
[GmsClient] 	at android.os.Handler.dispatchMessage(Handler.java:99)
[GmsClient] 	at android.os.Looper.loopOnce(Looper.java:201)
[GmsClient] 	at android.os.Looper.loop(Looper.java:288)
[GmsClient] 	at android.os.HandlerThread.run(HandlerThread.java:67)
[EGL_emulation] app_time_stats: avg=1.86ms min=1.18ms max=4.24ms count=60
[DOTNET] 2023-01-12 13:57:18.885 Info: Connected to endpoint '3.210.32.164:443' (from '10.0.2.16:45888')
[EGL_emulation] app_time_stats: avg=1.78ms min=1.09ms max=3.66ms count=60
[DOTNET] 2023-01-12 13:57:19.276 Info: Verifying server SSL certificate using 155 root certificates
[EGL_emulation] app_time_stats: avg=1.82ms min=1.18ms max=3.29ms count=60
[DOTNET] 2023-01-12 13:57:20.654 Info: Connection[1]: Session[1]: Received: ERROR "Client tried to connect using flexible sync before initial sync is complete" (error_code=229, try_again=true, error_action=Transient)
[DOTNET] 2023-01-12 13:57:20.655 Info: Connection[1]: Disconnected
[EGL_emulation] app_time_stats: avg=1.92ms min=1.11ms max=3.93ms count=61
[EGL_emulation] app_time_stats: avg=1.83ms min=1.22ms max=5.71ms count=60
[JavaBinder] !!! FAILED BINDER TRANSACTION !!!  (parcel size = 316)

The error you’re getting - Client tried to connect using flexible sync before initial sync is complete indicates that the server is still initializing sync. Generally that shouldn’t take a whole lot of time and only happens the first time you enable sync. If it doesn’t go away after a while, it likely indicates some issue with the server and/or your cluster (e.g. maybe you have a whole lot of data on a very small cluster).

You could check the server logs for any errors that could provide more insight into why initial sync is taking so long. If there’s nothing useful there, your best bet would be to open a support ticket and someone from the server team will investigate further.