Hello!
I have implemented client reset functionality, but I have not any idea how to simulate a client reset request to test the functionality. So could you guide to me how can I easily do that?
Thank you.
Hello!
I have implemented client reset functionality, but I have not any idea how to simulate a client reset request to test the functionality. So could you guide to me how can I easily do that?
Thank you.
you can force a client reset by changing the schema in Atlas. Note that you have to stop Sync to do this and restart it afterwards.
Doing this will send a client reset request to the client where you can handle it with your client reset functionality.
Our documentation shows an example on how to handle this request while the app is running and what to do if the client reset fails (which essentially means restarting the app and by that re-downloading the Realm).
Let me know if you have any other questions.
Best,
Dominic
HI @Dominic_Frei. Thank you for your response. I have followed the example that you have mentioned above and I do
realm.Dispose();
clientResetException.InitiateClientReset();
when a client reset exception emits. Also, I tried to simulate the client reset by
None of these cases emerged a client reset request, and I guess I do something wrong.
Before the schema change, I paused the sync, then made the change, then resume realm-sync but nothing happened.
would you mind sharing your code so we can look at it together?
Is the client reset functionality added to the session error handler?
What happens when you restart? Does the change actually appear?
Is data reset?
All this would indicate to me that the client reset request reaches your app but Iâm just speculating.
Looking at the code might give us more clues.
Sure. I have the following classes:
public interface IRealmSyncSessionExceptionHandler
{
void StartMonitoringSessionExceptions();
void StopMonitoringSessionExceptions();
}
The App.Xaml.cs inherits IRealmSyncSessionExceptionHandler
public partial class App : IRealmSyncSessionExceptionHandler
{
private IDisposable _sessionOnErrorDisposable;
public void StartMonitoringSessionExceptions()
{
var schedulerProvider = Container.Resolve<ISchedulerProvider>();
IObservable<EventPattern<ErrorEventArgs>> sessionOnErrorObservable = Observable.FromEventPattern<ErrorEventArgs>(handler => Session.Error += handler,
handler => Session.Error -= handler);
_sessionOnErrorDisposable = sessionOnErrorObservable
.SubscribeOn(schedulerProvider.ThreadPool)
.ObserveOn(schedulerProvider.CurrentSynchronizationContext)
.SubscribeAsync(async x => await SessionOnErrorAsync(x.Sender, x.EventArgs));
}
public void StopMonitoringSessionExceptions()
{
_sessionOnErrorDisposable.Dispose();
}
private async Task SessionOnErrorAsync(object sender, ErrorEventArgs e)
{
var session = (Session)sender;
_logger.Error(e.Exception, "Realm session raised an exception for user {UserId} with database {DatabasePath}", session.Path, session.User.Id);
if(e.Exception is ClientResetException clientResetException)
{
await OnClientResetRequested(session, clientResetException);
}
}
private async Task OnClientResetRequested(Session session, ClientResetException clientResetException)
{
_logger.Error("Client ResetAsync requested for " + session.Path + "due to " + clientResetException.Message);
var pageDialogService = Container.Resolve<IPageDialogService>();
// Prompt user to perform client reset immediately. If they don't do it,
// they won't receive any data from the server until they restart the app
// and all changes they make will be discarded when the app restarts.
bool shouldConfirmReset = await pageDialogService.DisplayAlertAsync(CommonStrings.CloudSyncTerminatedDialogTitle,
CommonStrings.ClientResetRequestedMessage,
CommonStrings.ResetNow,
CommonStrings.ResetLater);
if(shouldConfirmReset)
{
bool didReset = await Container.Resolve<IClientResetService>().ResetAsync(clientResetException);
if(didReset)
{
// Navigate the user back to the main page or reopen the
// the Realm and reinitialize the current page.
Restart();
}
else
{
// ResetAsync failed - notify user that they'll need to restart the app.
await pageDialogService.DisplayAlertAsync(CommonStrings.Warning,
CommonStrings.ClientResetFailedMessage,
CommonStrings.Ok);
}
}
}
}
Here is the client reset interface and its implementation:
public interface IClientResetService
{
/// <summary>
/// Initiates the client reset process.
/// </summary>
/// <returns><c>true</c> if actions were run successfully, <c>false</c> otherwise.</returns>
/// <remarks>
/// On Windows, all Realm instances for that path must be disposed before this method is called or an
/// Exception will be thrown.
/// </remarks>
public Task<bool> ResetAsync(ClientResetException clientResetException, CancellationToken token = default);
}
internal class ClientResetService : IClientResetService
{
private readonly IRealmFactory _realmFactory;
private readonly IDatabaseManager _databaseManager;
public ClientResetService(IRealmFactory realmFactory,
IDatabaseManager databaseManager)
{
_databaseManager = databaseManager;
_realmFactory = realmFactory;
}
public async Task<bool> ResetAsync(ClientResetException clientResetException, CancellationToken token = default)
{
Realm realm = await _realmFactory.GetRealmAsync(_databaseManager.CurrentDatabase);
// Close the Realm before doing the reset as it'll need
// to be deleted and all objects obtained from it will be
// invalidated.
realm.Dispose();
return clientResetException.InitiateClientReset();
}
}
Thank you for sharing the code. Nothing caught my idea immediately but let me understand something else a bit better first:
Related to the first point.
Actually, I did not have a chance to understand how the reset works or even it works or not because I am still not able to reproduce a client reset exception.
Second I havenât completely understood what should I do on my side (The client-side) when the client reset requests. Does the clientResetException.InitiateClientReset()
is enough or should I remove the current database and reinstall it again (download the database from realm cloud).
One more thing that I have noticed during testing.
When I receive the client reset exception (when re-launching the application), I do reset and restart the application (dispose DI container and call App.OnInitialized()), the client reset exception rises again which, causes an application crash. And when I re-launch the application, the exception does not rise.
This is a great step forward in figuring out whatâs wrong. Since you receive the client reset after restart my expectation would be that the changes you apply in Atlas lead to the correct result. Which then leads me to think that the problem lies within catching the exception.
But when you say I do receive the client reset exception after the app is restarted.
youâre referring to the very same code right? So, if I understand correctly, the error doesnât fire until you restart the app?
Yes, I am referring to the same code (almost the same) and, yes, You are correct. The error doesnât fire until I restart (re-launch) the app. I assume that behavior is not expected and, the app should receive real-time client reset exception.
Some details which discovered during the investigation.
Iâve had a chat with @nirinchev about that. He explained that pausing the Sync will lead to a 503 which leads to the app trying to reconnect after a while. Maybe you closed the app right before the next successful reconnect (which would only happen after Sync was resumed) happened?
What happens if you keep the app open for a little longer after resuming Sync?
Thanks for those details!
Those exception, do you receive them during your client reset handling or somewhere else? How do you handle them?
If I understand correctly, (7) does not lead to an exception but also does not lead to a client reset correct?
btw: This link is for your account. I canât access your data.
Thank you for the update. I canât see anything wrong with that straight away.
Can you give https://docs.mongodb.com/realm/sdk/dotnet/advanced-guides/client-reset/ a try? And use the code and explanation right from the documentation? As I see it right now that should be the best option to figure out where in that documentation we might have missed out on something that you just discovered.
Thanks!
The sad thing is that I have already followed that sample and currently have an issue related to the not throwing client reset exception. Thanks for your response. I will continue my investigations.
After some investigation, we found that to simulate client reset exceptions in real-time we need to make destructive changes without pausing sync.
Also, we have faced up some other issues which are discussed here.
This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.