Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync session is resumed without explicitly calling resume #6085

Closed
edualonso opened this issue Dec 6, 2022 · 10 comments · Fixed by #6183
Closed

Sync session is resumed without explicitly calling resume #6085

edualonso opened this issue Dec 6, 2022 · 10 comments · Fixed by #6183
Assignees

Comments

@edualonso
Copy link
Contributor

Say I have two clients connected to the same app. Client A pauses its session and while being paused writes something. Client B will receive those updates regardless.

I can confirm the session becomes active again after calling realm_begin_write.

@sync-by-unito
Copy link

sync-by-unito bot commented Dec 6, 2022

➤ nicola-cab commented:

Maybe this is something Jonathan can help you with.

@sync-by-unito
Copy link

sync-by-unito bot commented Dec 6, 2022

➤ Jonathan Reams commented:

I'm gonna need more information. Do you have debug-level logs? What does the repro for this look like exactly?

@edualonso
Copy link
Contributor Author

I wrote a VERY simple test that calls session.pause() and then runs a transaction, not necessarily writing anything:

            println("----------------> BEFORE CALLING session.pause")
            realmA.syncSession.pause()
            println("----------------> AFTER  CALLING session.pause")
            async {
                assertEquals(SyncSession.State.INACTIVE, realmA.syncSession.state)
                realmA.write {
                    //  write something
                }
                assertEquals(SyncSession.State.INACTIVE, realmA.syncSession.state) // FAILS, session is ACTIVE even though we haven't called session.resume()
            }

I get this output:

2022-12-06 15:08:53.485 29298-29321 SYNC                    io.realm.sync.testapp.test           D  App: register_email: ovoihnpj7ee6ze7syovm@10gen.com
2022-12-06 15:08:53.489 29298-29323 REALM                   io.realm.sync.testapp.test           D  REQUEST: http://127.0.0.1:9090/api/client/v2.0/app/test-app-partition-aiunl/location
                                                                                                    METHOD: HttpMethod(value=GET)
                                                                                                    BODY Content-Type: null
                                                                                                    BODY START
                                                                                                    
                                                                                                    BODY END
2022-12-06 15:08:53.494 29298-29339 REALM                   io.realm.sync.testapp.test           D  RESPONSE: 200 OK
                                                                                                    METHOD: HttpMethod(value=GET)
                                                                                                    FROM: http://127.0.0.1:9090/api/client/v2.0/app/test-app-partition-aiunl/location
                                                                                                    BODY Content-Type: application/json
                                                                                                    BODY START
                                                                                                    {"deployment_model":"GLOBAL","location":"US-VA","hostname":"http://127.0.0.1:9090","ws_hostname":"ws://localhost:9090"}
                                                                                                    BODY END
2022-12-06 15:08:53.502 29298-29323 SYNC                    io.realm.sync.testapp.test           D  App: update_hostname: http://127.0.0.1:9090 | ws://localhost:9090
2022-12-06 15:08:53.505 29298-29323 REALM                   io.realm.sync.testapp.test           D  REQUEST: http://127.0.0.1:9090/api/client/v2.0/app/test-app-partition-aiunl/auth/providers/local-userpass/register
                                                                                                    METHOD: HttpMethod(value=POST)
                                                                                                    BODY Content-Type: application/json; charset=utf-8
                                                                                                    BODY START
                                                                                                    {"email":"ovoihnpj7ee6ze7syovm@10gen.com","password":"password1234"}
                                                                                                    BODY END
2022-12-06 15:08:53.528 29298-29339 REALM                   io.realm.sync.testapp.test           D  RESPONSE: 201 Created
                                                                                                    METHOD: HttpMethod(value=POST)
                                                                                                    FROM: http://127.0.0.1:9090/api/client/v2.0/app/test-app-partition-aiunl/auth/providers/local-userpass/register
                                                                                                    BODY Content-Type: application/json
                                                                                                    BODY START
                                                                                                    {}
                                                                                                    BODY END
2022-12-06 15:08:53.530 29298-29321 SYNC                    io.realm.sync.testapp.test           D  App: log_in_with_credentials: app_id: test-app-partition-aiunl - app_version: APP_VERSION
2022-12-06 15:08:53.530 29298-29321 SYNC                    io.realm.sync.testapp.test           D  App: version info: platform: Android/JVM  version: Android/JVM - sdk version: 1.6.0-SNAPSHOT - core version: 13.0.0
2022-12-06 15:08:53.531 29298-29323 REALM                   io.realm.sync.testapp.test           D  REQUEST: http://127.0.0.1:9090/api/client/v2.0/app/test-app-partition-aiunl/auth/providers/local-userpass/login
                                                                                                    METHOD: HttpMethod(value=POST)
                                                                                                    BODY Content-Type: application/json; charset=utf-8
                                                                                                    BODY START
                                                                                                    {"provider":"local-userpass","username":"ovoihnpj7ee6ze7syovm@10gen.com","password":"password1234","options":{"device":{"appVersion":"APP_VERSION","appId":"test-app-partition-aiunl","platform":"Android/JVM","platformVersion":"13","sdkVersion":"1.6.0-SNAPSHOT","coreVersion":"13.0.0"}}}
                                                                                                    BODY END
2022-12-06 15:08:53.591 29298-29339 REALM                   io.realm.sync.testapp.test           D  RESPONSE: 200 OK
                                                                                                    METHOD: HttpMethod(value=POST)
                                                                                                    FROM: http://127.0.0.1:9090/api/client/v2.0/app/test-app-partition-aiunl/auth/providers/local-userpass/login
                                                                                                    BODY Content-Type: application/json
                                                                                                    BODY START
                                                                                                    {"access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjYzOGY0YmNhZTFjOGRlMmNhODhhN2IyYSIsInR5cCI6IkpXVCJ9.eyJiYWFzX2RldmljZV9pZCI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlNyIsImJhYXNfZG9tYWluX2lkIjoiNjM4ZjRiYzllMWM4ZGUyY2E4OGE3YjI5IiwiZXhwIjoxNjcwMzM3NTM1LCJpYXQiOjE2NzAzMzU3MzUsImlzcyI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlOCIsInN0aXRjaF9kZXZJZCI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlNyIsInN0aXRjaF9kb21haW5JZCI6IjYzOGY0YmM5ZTFjOGRlMmNhODhhN2IyOSIsInN1YiI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlNSIsInR5cCI6ImFjY2VzcyJ9.ezZOO25WNMGbQ8HLjgPdu9dnZzDxx7gN-imkqTywnfoEPYSb38JLo1zmkV-VL1f2dzGAcz2qkuzdLBzmW6QmcUutz4feYZUEGX6RrdUK5y5pgTaAxH4gEo4GM9o_eRQqIjmxYtF1mQnWKldu3EMWU_wo9R6QXII8znUvAVvdggW1lY_HiPYjZZ29duJ4KYsE6kuBMZrkIDV12UateZWDe4V0UvmOP7eEQJwmuoZwu7oiozqn8ZwyZMYufGkFVjWgkF3Dekrf5DA-mm-USArcC39pSMUgd8lGXU0iH-ep1zY5kUuVNqFcqAJzj_N_MWjJEuB4BT7oSHUeR25j0C7lRA","refresh_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjYzOGY0YmNhZTFjOGRlMmNhODhhN2IyYSIsInR5cCI6IkpXVCJ9.eyJiYWFzX2RhdGEiOm51bGwsImJhYXNfZGV2aWNlX2lkIjoiNjM4ZjRjZjdlMWM4ZGUyY2E4OGE3Y2U3IiwiYmFhc19kb21haW5faWQiOiI2MzhmNGJjOWUxYzhkZTJjYTg4YTdiMjkiLCJiYWFzX2lkIjoiNjM4ZjRjZjdlMWM4ZGUyY2E4OGE3Y2U4IiwiYmFhc19pZGVudGl0eSI6eyJpZCI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlMiIsInByb3ZpZGVyX3R5cGUiOiJsb2NhbC11c2VycGFzcyIsInByb3ZpZGVyX2lkIjoiNjM4ZjRiY2RlMWM4ZGUyY2E4OGE3YjVmIn0sImV4cCI6MTY3NTUxOTczNSwiaWF0IjoxNjcwMzM1NzM1LCJzdGl0Y2hfZGF0YSI6bnVsbCwic3RpdGNoX2RldklkIjoiNjM4ZjRjZjdlMWM4ZGUyY2E4OGE3Y2U3Iiwic3RpdGNoX2RvbWFpbklkIjoiNjM4ZjRiYzllMWM4ZGUyY2E4OGE3YjI5Iiwic3RpdGNoX2lkIjoiNjM4ZjRjZjdlMWM4ZGUyY2E4OGE3Y2U4Iiwic3RpdGNoX2lkZW50Ijp7ImlkIjoiNjM4ZjRjZjdlMWM4ZGUyY2E4OGE3Y2UyIiwicHJvdmlkZXJfdHlwZSI6ImxvY2FsLXVzZXJwYXNzIiwicHJvdmlkZXJfaWQiOiI2MzhmNGJjZGUxYzhkZTJjYTg4YTdiNWYifSwic3ViIjoiNjM4ZjRjZjdlMWM4ZGUyY2E4OGE3Y2U1IiwidHlwIjoicmVmcmVzaCJ9.I0rKPGYhDga7FWuuVccndyC-x3uD3XoHdnUoM_yVbxCu9aIDTIOkV2a0LJsGeQUbJiYRHYYOC_-sw9d4pSO-xSuy5bwzJcdYWz_ykO5_P_xHAj9NsW6JuYNhGIvp9IZVmpMScUfG2_LLKQJEhjc19nMLSLGy4LMLGkGDV10OFU7QxNoWDmNJ9zq5ePz0yzMPc8gkrhT6svdgZ6sUf8bbUVhURQBfEX4Sx1fFjnz0O7zHN7oMlFjGHbMH6fUdi7n94wGCZpaemhKfc82cXW6ELolKPPESdtR4I2WeWEH64Yb0ey_pfs8FnJkWsTqckrUzcEEkgmRuLOGuWLzdVjLRRQ","user_id":"638f4cf7e1c8de2ca88a7ce5","device_id":"638f4cf7e1c8de2ca88a7ce7"}
                                                                                                    BODY END
2022-12-06 15:08:53.600 29298-29323 SYNC                    io.realm.sync.testapp.test           D  App: do_authenticated_request: GET http://127.0.0.1:9090/api/client/v2.0/auth/profile
2022-12-06 15:08:53.601 29298-29323 REALM                   io.realm.sync.testapp.test           D  REQUEST: http://127.0.0.1:9090/api/client/v2.0/auth/profile
                                                                                                    METHOD: HttpMethod(value=GET)
                                                                                                    BODY Content-Type: null
                                                                                                    BODY START
                                                                                                    
                                                                                                    BODY END
2022-12-06 15:08:53.614 29298-29325 REALM                   io.realm.sync.testapp.test           D  RESPONSE: 200 OK
                                                                                                    METHOD: HttpMethod(value=GET)
                                                                                                    FROM: http://127.0.0.1:9090/api/client/v2.0/auth/profile
                                                                                                    BODY Content-Type: application/json
                                                                                                    BODY START
                                                                                                    {"user_id":"638f4cf7e1c8de2ca88a7ce5","domain_id":"638f4bc9e1c8de2ca88a7b29","identities":[{"id":"638f4cf7e1c8de2ca88a7ce2","provider_type":"local-userpass","provider_id":"638f4bcde1c8de2ca88a7b5f"}],"data":{"email":"ovoihnpj7ee6ze7syovm@10gen.com"},"type":"normal"}
                                                                                                    BODY END
2022-12-06 15:08:53.663 29298-29321 REALM                   io.realm.sync.testapp.test           D  Realm opened: /data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Realm sync client ([realm-core-13.0.0])
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Supported protocol versions: 2-7
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Platform: Android Linux 5.15.41-android13-8-00205-gf1bf82c3dacd-ab8747247 #1 SMP PREEMPT Sun Jun 19 02:44:07 UTC 2022 aarch64
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Build mode: Debug
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: one_connection_per_session = true
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: connect_timeout = 120000 ms
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: connection_linger_time = 30000 ms
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: ping_keepalive_period = 60000 ms
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: pong_keepalive_timeout = 120000 ms
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: fast_reconnect_limit = 60000 ms
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: disable_upload_compaction = false
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  Config param: disable_sync_to_disk = false
2022-12-06 15:08:53.669 29298-29321 SYNC                    io.realm.sync.testapp.test           D  User agent string: 'RealmSync/13.0.0 (Android Linux 5.15.41-android13-8-00205-gf1bf82c3dacd-ab8747247 #1 SMP PREEMPT Sun Jun 19 02:44:07 UTC 2022 aarch64)  '
2022-12-06 15:08:53.670 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: Binding '/data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm' to '"partition-375419441997845467"'
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: Activating
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: client_reset_config = false, Realm exists = true, client reset = false
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: client_file_ident = 0, client_file_ident_salt = 0
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: last_version_available  = 0
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: progress_server_version = 0
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: progress_client_version = 0
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 0, reliable_download_progress = false, snapshot version = 1
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  WebSocket::Websocket()
2022-12-06 15:08:53.671 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Resolving 'localhost:9090'
2022-12-06 15:08:53.674 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 112, reliable_download_progress = false, snapshot version = 2
2022-12-06 15:08:53.674 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 112, reliable_download_progress = false, snapshot version = 2
2022-12-06 15:08:53.676 29298-29321 REALM                   io.realm.sync.testapp.test           D  Realm opened: /data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm
2022-12-06 15:08:53.677 29298-29321 System.out              io.realm.sync.testapp.test           I  ----------------> BEFORE CALLING session.pause
2022-12-06 15:08:53.678 29298-29321 System.out              io.realm.sync.testapp.test           I  ----------------> AFTER  CALLING session.pause
2022-12-06 15:08:53.678 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: Initiating deactivation
2022-12-06 15:08:53.678 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Session[1]: Deactivation completed
2022-12-06 15:08:53.678 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Allowing reconnection in 792 milliseconds
2022-12-06 15:08:53.678 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Disconnected
2022-12-06 15:08:53.678 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Destroying connection object
2022-12-06 15:08:53.681 29298-29321 System.out              io.realm.sync.testapp.test           I  ----------------> RealmImpl.write 1
2022-12-06 15:08:53.681 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 1
2022-12-06 15:08:53.681 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 2
2022-12-06 15:08:53.681 29298-29347 REALM                   io.realm.sync.testapp.test           D  Realm opened: /data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Binding '/data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm' to '"partition-375419441997845467"'
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Activating
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: client_reset_config = false, Realm exists = true, client reset = false
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: client_file_ident = 0, client_file_ident_salt = 0
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: last_version_available  = 2
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: progress_server_version = 0
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: progress_client_version = 0
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 112, reliable_download_progress = false, snapshot version = 2
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  WebSocket::Websocket()
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Resolving 'localhost:9090'
2022-12-06 15:08:53.682 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 3
2022-12-06 15:08:53.682 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 4
2022-12-06 15:08:53.682 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 5
2022-12-06 15:08:53.682 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 6
2022-12-06 15:08:53.682 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 6a
2022-12-06 15:08:53.683 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connecting to endpoint '127.0.0.1:9090' (1/1)
2022-12-06 15:08:53.684 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connected to endpoint '127.0.0.1:9090' (from '127.0.0.1:38620')
2022-12-06 15:08:53.684 29298-29348 SYNC                    io.realm.sync.testapp.test           D  WebSocket::initiate_client_handshake()
2022-12-06 15:08:53.684 29298-29348 SYNC                    io.realm.sync.testapp.test           V  HTTP request =
                                                                                                    GET /api/client/v2.0/app/test-app-partition-aiunl/realm-sync?baas_at=eyJhbGciOiJSUzI1NiIsImtpZCI6IjYzOGY0YmNhZTFjOGRlMmNhODhhN2IyYSIsInR5cCI6IkpXVCJ9.eyJiYWFzX2RldmljZV9pZCI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlNyIsImJhYXNfZG9tYWluX2lkIjoiNjM4ZjRiYzllMWM4ZGUyY2E4OGE3YjI5IiwiZXhwIjoxNjcwMzM3NTM1LCJpYXQiOjE2NzAzMzU3MzUsImlzcyI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlOCIsInN0aXRjaF9kZXZJZCI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlNyIsInN0aXRjaF9kb21haW5JZCI6IjYzOGY0YmM5ZTFjOGRlMmNhODhhN2IyOSIsInN1YiI6IjYzOGY0Y2Y3ZTFjOGRlMmNhODhhN2NlNSIsInR5cCI6ImFjY2VzcyJ9.ezZOO25WNMGbQ8HLjgPdu9dnZzDxx7gN-imkqTywnfoEPYSb38JLo1zmkV-VL1f2dzGAcz2qkuzdLBzmW6QmcUutz4feYZUEGX6RrdUK5y5pgTaAxH4gEo4GM9o_eRQqIjmxYtF1mQnWKldu3EMWU_wo9R6QXII8znUvAVvdggW1lY_HiPYjZZ29duJ4KYsE6kuBMZrkIDV12UateZWDe4V0UvmOP7eEQJwmuoZwu7oiozqn8ZwyZMYufGkFVjWgkF3Dekrf5DA-mm-USArcC39pSMUgd8lGXU0iH-ep1zY5kUuVNqFcqAJzj_N_MWjJEuB4BT7oSHUeR25j0C7lRA HTTP/1.1
                                                                                                    Host: localhost:9090
                                                                                                    Connection: Upgrade
                                                                                                    Sec-WebSocket-Key: WbF1XGgFxIFU0Q9EbRv+tQ==
                                                                                                    Sec-WebSocket-Protocol: com.mongodb.realm-sync/7, com.mongodb.realm-sync/6, com.mongodb.realm-sync/5, com.mongodb.realm-sync/4, com.mongodb.realm-sync/3, com.mongodb.realm-sync/2
                                                                                                    Sec-WebSocket-Version: 13
                                                                                                    Upgrade: websocket
                                                                                                    User-Agent: RealmSync/13.0.0 (Android Linux 5.15.41-android13-8-00205-gf1bf82c3dacd-ab8747247 #1 SMP PREEMPT Sun Jun 19 02:44:07 UTC 2022 aarch64)
2022-12-06 15:08:53.686 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 112, reliable_download_progress = false, snapshot version = 3
2022-12-06 15:08:53.686 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 112, reliable_download_progress = false, snapshot version = 3
2022-12-06 15:08:53.686 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 7
2022-12-06 15:08:53.686 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 8
2022-12-06 15:08:53.686 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 9
2022-12-06 15:08:53.687 29298-29321 System.out              io.realm.sync.testapp.test           I  ----------------> RealmImpl.write 2
2022-12-06 15:08:53.687 29298-29321 REALM                   io.realm.sync.testapp.test           D  Updating Realm version: VersionId(version=2) -> VersionId(version=3)
2022-12-06 15:08:53.688 29298-29321 System.out              io.realm.sync.testapp.test           I  ----------------> RealmImpl.write 3
2022-12-06 15:08:53.691 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Initiating deactivation
2022-12-06 15:08:53.691 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Deactivation completed
2022-12-06 15:08:53.691 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Allowing reconnection in 881 milliseconds
2022-12-06 15:08:53.691 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Disconnected
2022-12-06 15:08:53.691 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Destroying connection object
2022-12-06 15:08:53.695 29298-29323 REALM                   io.realm.sync.testapp.test           D  REQUEST: http://127.0.0.1:9090/api/client/v2.0/auth/session
                                                                                                    METHOD: HttpMethod(value=DELETE)
                                                                                                    BODY Content-Type: application/json; charset=utf-8
                                                                                                    BODY START
                                                                                                    
                                                                                                    BODY END
2022-12-06 15:08:53.730 29298-29335 REALM                   io.realm.sync.testapp.test           D  RESPONSE: 204 No Content
                                                                                                    METHOD: HttpMethod(value=DELETE)
                                                                                                    FROM: http://127.0.0.1:9090/api/client/v2.0/auth/session
                                                                                                    BODY Content-Type: null
                                                                                                    BODY START
                                                                                                    
                                                                                                    BODY END
2022-12-06 15:08:53.831 29298-29321 TestRunner              io.realm.sync.testapp.test           E  failed: writingLocallyShouldNotResumeSession(io.realm.kotlin.test.mongodb.shared.SyncSessionTests)
2022-12-06 15:08:53.831 29298-29321 TestRunner              io.realm.sync.testapp.test           E  ----- begin exception -----
2022-12-06 15:08:53.831 29298-29321 TestRunner              io.realm.sync.testapp.test           E  java.lang.AssertionError: expected:<INACTIVE> but was:<ACTIVE>
                                                                                                    	at org.junit.Assert.fail(Assert.java:89)

I can highlight the following. Pausing the session works just fine:

2022-12-06 15:08:53.678 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[1]: Disconnected

But it appears the session is resumed right after calling realm_begin_write:

2022-12-06 15:08:53.681 29298-29347 System.out              io.realm.sync.testapp.test           I  ----------------> SuspendableWriter.write 2 -> calls realm_begin_write
2022-12-06 15:08:53.681 29298-29347 REALM                   io.realm.sync.testapp.test           D  Realm opened: /data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Binding '/data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm' to '"partition-375419441997845467"'
2022-12-06 15:08:53.682 29298-29348 SYNC                    io.realm.sync.testapp.test           D  Connection[2]: Session[2]: Activating

@sync-by-unito
Copy link

sync-by-unito bot commented Dec 13, 2022

➤ Jonathan Reams commented:

Just want to run a theory by you. Looking at the logs we see Realm opened: /data/user/0/io.realm.sync.testapp.test/files/mongodb-realm/test-app-partition-aiunl/638f4cf7e1c8de2ca88a7ce5/s_partition-375419441997845467.realm right before the session is resumed. Looks like that's getting logged from here https://github.com/realm/realm-kotlin/blob/e6b3136b0f659d406ddb51fc4d76be09f71afec7/packages/library-base/src/commonMain/kotlin/io/realm/kotlin/internal/BaseRealmImpl.kt#L61, which would seem to indicate you're re-initializing the realm within the async write block. Is it possible that when you schedule the write asynchronously, the realm is going out of scope and getting closed and then re-opened again in the async block, and that since the sync session was already closed, when it gets re-opened it gets restarted?

@edualonso
Copy link
Contributor Author

I don't think so. The second "Realm opened" entry you see is our "writer" Realm, which is lazily initialised from the "reader" realm when we run a write transaction for the first time. This logic has been there for quite a while.
I've also converted the test to be synchronous and it still fails. I can launch queries at any given time during the test and the instance isn't recreated.

@sync-by-unito
Copy link

sync-by-unito bot commented Dec 14, 2022

➤ Jonathan Reams commented:

So I'm trying to come up with a repro for this using the C API. So far I've got this integration test

TEST_CASE("app: uploads do not unexpectedly resume", "[sync][app]") {
    std::string base_url = get_base_url();
    REQUIRE(!base_url.empty());

    Schema schema{
        {"TopLevel",
         {
             {"_id", PropertyType::ObjectId, Property::IsPrimary{true}},
         }},
    };

    auto server_app_config = minimal_app_config(base_url, "set_new_embedded_object", schema);
    auto app_session = create_app(server_app_config);
    auto partition = random_string(100);

    util::StderrLogger logger;
    logger.info("creating new realm");

    TestAppSession test_session(app_session, nullptr, DeleteApp{false});
    SyncTestFile config(test_session.app(), partition, schema);
    realm_t c_wrap_realm(Realm::get_shared_realm(config));
    auto sync_session = realm_sync_session_get(&c_wrap_realm);

    logger.info("pausing sync session");
    realm_sync_session_pause(sync_session);

    auto state = realm_sync_session_get_state(sync_session);
    REQUIRE(state == RLM_SYNC_SESSION_STATE_INACTIVE);

    // Sleep to give time for the sync session to actually be tore down.
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    logger.info("beginning write");
    realm_begin_write(&c_wrap_realm);

    // Sleep to make sure the sync session isn't actually starting back up here.
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    bool found_class = false;
    realm_class_info_t class_info;
    REQUIRE(realm_find_class(&c_wrap_realm, "TopLevel", &found_class, &class_info));
    REQUIRE(found_class);

    logger.info("creating object");
    auto obj =
        realm_object_create_with_primary_key(&c_wrap_realm, class_info.key, c_api::to_capi(Mixed{ObjectId::gen()}));
    REQUIRE(obj);

    logger.info("committing");
    REQUIRE(realm_commit(&c_wrap_realm));

    // Sleep to make sure committing didn't trigger any kind of resume
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    logger.info("resuming");
    realm_sync_session_resume(sync_session);

    auto pf = util::make_promise_future<void>();
    auto unique_promise = std::make_unique<util::Promise<void>>(std::move(pf.promise));
    realm_sync_session_wait_for_upload_completion(
        sync_session,
        [](realm_userdata_t userdata, realm_sync_error_code_t* error) {
            REQUIRE(!error);
            auto promise = reinterpret_cast<util::Promise<void>*>(userdata);
            promise->emplace_value();
        },
        unique_promise.get(), [](realm_userdata_t) {});
    pf.future.get();

    realm_release(obj);
    realm_release(sync_session);
}

And every time it does what I'd expect it to do:

Filters: app: uploads do not unexpectedly resume
Randomness seeded to: 4057804793
creating new realm
Realm sync client ([realm-core-13.1.2])
Supported protocol versions: 2-7
Platform: macOS Darwin 21.6.0 Darwin Kernel Version 21.6.0: Thu Sep 29 20:13:56 PDT 2022; root:xnu-8020.240.7~1/RELEASE_ARM64_T6000 arm64
Build mode: Debug
Config param: one_connection_per_session = true
Config param: connect_timeout = 120000 ms
Config param: connection_linger_time = 30000 ms
Config param: ping_keepalive_period = 60000 ms
Config param: pong_keepalive_timeout = 120000 ms
Config param: fast_reconnect_limit = 60000 ms
Config param: disable_upload_compaction = false
Config param: disable_sync_to_disk = false
User agent string: 'RealmSync/13.1.2 (macOS Darwin 21.6.0 Darwin Kernel Version 21.6.0: Thu Sep 29 20:13:56 PDT 2022; root:xnu-8020.240.7~1/RELEASE_ARM64_T6000 arm64)  '
App: register_email: realm_tests_do_autoverifyJKpirOAtiy@TjPCOWtQoZ.com
App: update_hostname: http://localhost:9090 | ws://localhost:9090
App: log_in_with_credentials: app_id: set_new_embedded_object-kxcff - app_version: A Local App Version
App: version info: platform: Object Store Platform Tests  version: Object Store Platform Tests - sdk version: An sdk version - core version: 13.1.2
App: do_authenticated_request: GET http://localhost:9090/api/client/v2.0/auth/profile
Connection[1]: Session[1]: Binding '/var/folders/s3/rtk055q91y15yg1hg2c373w40000gp/T/realm_0KppBW/realm.G5ecRb' to '"kzmrNSVDcaZbIVKEGORnVKKNQicBGQhhihgPtYSTepuBtDSqFYbjRXigLPGalANKDqeTFrqKDFGOoTpovdFhxSlIAMpZsZVsHxfh"'
Connection[1]: Session[1]: Activating
Connection[1]: Session[1]: client_reset_config = false, Realm exists = true, client reset = false
Connection[1]: Session[1]: client_file_ident = 0, client_file_ident_salt = 0
Connection[1]: Session[1]: last_version_available  = 0
Connection[1]: Session[1]: progress_server_version = 0
Connection[1]: Session[1]: progress_client_version = 0
Connection[1]: Session[1]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 0, reliable_download_progress = false, snapshot version = 1
WebSocket::Websocket()
Resolving 'localhost:9090'
Connection[1]: Session[1]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 23, reliable_download_progress = false, snapshot version = 2
Connection[1]: Session[1]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 23, reliable_download_progress = false, snapshot version = 2
pausing sync session
Connection[1]: Session[1]: Initiating deactivation
Connection[1]: Session[1]: Deactivation completed
Connection[1]: Allowing reconnection in 923 milliseconds
Connection[1]: Disconnected
Connection[1]: Destroying connection object
beginning write
creating object
committing
resuming
Connection[2]: Session[2]: Binding '/var/folders/s3/rtk055q91y15yg1hg2c373w40000gp/T/realm_0KppBW/realm.G5ecRb' to '"kzmrNSVDcaZbIVKEGORnVKKNQicBGQhhihgPtYSTepuBtDSqFYbjRXigLPGalANKDqeTFrqKDFGOoTpovdFhxSlIAMpZsZVsHxfh"'
Connection[2]: Session[2]: Activating
Connection[2]: Session[2]: client_reset_config = false, Realm exists = true, client reset = false
Connection[2]: Session[2]: client_file_ident = 0, client_file_ident_salt = 0
Connection[2]: Session[2]: last_version_available  = 3
Connection[2]: Session[2]: progress_server_version = 0
Connection[2]: Session[2]: progress_client_version = 0
Connection[2]: Session[2]: Progress handler called, downloaded = 0, downloadable(total) = 0, uploaded = 0, uploadable = 49, reliable_download_progress = false, snapshot version = 3
WebSocket::Websocket()
Resolving 'localhost:9090'
Connecting to endpoint '127.0.0.1:9090' (1/2)
Connected to endpoint '127.0.0.1:9090' (from '127.0.0.1:65459')
WebSocket::initiate_client_handshake()
HTTP request =
GET /api/client/v2.0/app/set_new_embedded_object-kxcff/realm-sync?baas_at=eyJhbGciOiJSUzI1NiIsImtpZCI6IjYzOWEzZmUwYzVmMzhlYzkwYmFmYjZlNyIsInR5cCI6IkpXVCJ9.eyJiYWFzX2RldmljZV9pZCI6IjYzOWEzZmUwYzVmMzhlYzkwYmFmYjczOSIsImJhYXNfZG9tYWluX2lkIjoiNjM5YTNmZTBjNWYzOGVjOTBiYWZiNmU2IiwiZXhwIjoxNjcxMDU1MDgwLCJpYXQiOjE2NzEwNTMyODAsImlzcyI6IjYzOWEzZmUwYzVmMzhlYzkwYmFmYjczYSIsInN0aXRjaF9kZXZJZCI6IjYzOWEzZmUwYzVmMzhlYzkwYmFmYjczOSIsInN0aXRjaF9kb21haW5JZCI6IjYzOWEzZmUwYzVmMzhlYzkwYmFmYjZlNiIsInN1YiI6IjYzOWEzZmUwYzVmMzhlYzkwYmFmYjczNyIsInR5cCI6ImFjY2VzcyJ9.N2LhD9ZcP6BG2-Uwms_rQxhmHdzuY0pKEjje1mJM-uHizp9BATgsHY_MCokBjWL3QdPQRouEV2rBq5QhTPnIsGjToR7Qst0lQgVHFJ6wWxaibL6C1pHR9qljyw3_fo24v6rkxzv3C2yh2Epz0dV9efbO-ugncV_QvgYcqh9pFCA2AwKooVE29lqAzkw401YFRJir3SxqfejkuFqCpGNxIaetgrqP_JLhs7llO-fF2PHFz6XgVcsMumkTNWSqWBiSSTItLc1vjj2iMViUReGFYiZcJu1CrrO4GihXth4dy-Ir3EIFgHCmRRjQMMcmgLVQ2WAdjFVAFgfXeYRZBLFvxw HTTP/1.1
Host: localhost:9090
Connection: Upgrade
Sec-WebSocket-Key: YZ0gZNp2coDyRkXgSkwo/g==
Sec-WebSocket-Protocol: com.mongodb.realm-sync/7, com.mongodb.realm-sync/6, com.mongodb.realm-sync/5, com.mongodb.realm-sync/4, com.mongodb.realm-sync/3, com.mongodb.realm-sync/2
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: RealmSync/13.1.2 (macOS Darwin 21.6.0 Darwin Kernel Version 21.6.0: Thu Sep 29 20:13:56 PDT 2022; root:xnu-8020.240.7~1/RELEASE_ARM64_T6000 arm64)


WebSocket::handle_http_response_received()
HTTP response = HTTP/1.1 101 Switching Protocols
Cache-Control: no-cache, no-store, must-revalidate
Connection: Upgrade
Sec-Websocket-Accept: cunyk+NNF8OU08AOP0PzdYuBC4Y=
Sec-Websocket-Protocol: com.mongodb.realm-sync/7
Strict-Transport-Security: max-age=86400; includeSubdomains;
Upgrade: websocket
Vary: Origin
X-Appservices-Request-Id: 639a3fe2c5f38ec90bafb75e
X-Frame-Options: DENY


Connection[2]: Negotiated protocol version: 7
Connection[2]: Will emit a ping in 20213 milliseconds
Connection[2]: Session[2]: Received: IDENT(client_file_ident=1, client_file_ident_salt=3727518412418838230)
Connection[2]: Session[2]: Sending: IDENT(client_file_ident=1, client_file_ident_salt=3727518412418838230, scan_server_version=0, scan_client_version=0, latest_server_version=0, latest_server_version_salt=0)
Connection[2]: Session[2]: Sending: MARK(request_ident=1)
Connection[2]: Download message compression: is_body_compressed = false, compressed_body_size=66, uncompressed_body_size=66
Connection[2]: Received: DOWNLOAD CHANGESET(server_version=1, client_version=0, origin_timestamp=250982882524, origin_file_ident=2, original_changeset_size=41, changeset_size=41)
Connection[2]: Changeset: 3F 00 08 54 6F 70 4C 65 76 65 6C 3F 01 03 5F 69 64 3F 02 09 70 61 72 74 69 74 69 6F 6E 00 00 00 01 0A 00 06 00 02 03 01 00
Connection[2]: Changeset (parsed):
InternStrings   0="TopLevel", 1="_id", 2="partition"
AddTable        path="TopLevel", pk_field="_id", pk_type=ObjectId, pk_nullable=0, is_asymmetric=0
AddColumn       table="TopLevel", field="partition", type=String, nullable=1, collection_type=Single

Connection[2]: Session[2]: Received: DOWNLOAD(download_server_version=1, download_client_version=0, latest_server_version=1, latest_server_version_salt=7572542647863107228, upload_client_version=0, upload_server_version=0, downloadable_bytes=0, last_in_batch=true, query_version=0, num_changesets=1, ...)
Connection[2]: Session[2]: Scanning incoming changeset [1/1] (2 instructions)
Connection[2]: Session[2]: Scanning local changeset [1/2] (1 instructions)
Connection[2]: Session[2]: Scanning local changeset [2/2] (1 instructions)
Connection[2]: Session[2]: Indexing incoming changeset [1/1] (2 instructions)
Connection[2]: Session[2]: Finished changeset indexing (incoming: 1 changeset(s) / 2 instructions, local: 2 changeset(s) / 2 instructions, conflict group(s): 2)
Connection[2]: Session[2]: Transforming local changeset [1/2] through 1 incoming changeset(s) with 2 conflict group(s)
Connection[2]: Session[2]: Transforming local changeset [2/2] through 1 incoming changeset(s) with 2 conflict group(s)
Connection[2]: Session[2]: Finished transforming 2 local changesets through 1 incoming changesets (2 vs 2 instructions, in 2 conflict groups)
Connection[2]: Session[2]: Integrated 1 changesets out of 1
Connection[2]: Session[2]: 1 remote changeset integrated, producing client version 5
Connection[2]: Session[2]: Progress handler called, downloaded = 41, downloadable(total) = 41, uploaded = 0, uploadable = 49, reliable_download_progress = true, snapshot version = 5
Connection[2]: Session[2]: Progress handler called, downloaded = 41, downloadable(total) = 41, uploaded = 0, uploadable = 49, reliable_download_progress = true, snapshot version = 5
Connection[2]: Session[2]: Received: MARK(request_ident=1)
Connection[2]: Session[2]: Sending: UPLOAD(progress_client_version=5, progress_server_version=1, locked_server_version=1, num_changesets=2)
Connection[2]: Session[2]: Fetching changeset for upload (client_version=2, server_version=0, changeset_size=23, origin_timestamp=250982880921, origin_file_ident=0)
Connection[2]: Session[2]: Changeset: 3F 00 08 54 6F 70 4C 65 76 65 6C 3F 01 03 5F 69 64 00 00 00 01 0A 00
Connection[2]: Session[2]: Changeset (parsed):
InternStrings   0="TopLevel", 1="_id"
AddTable        path="TopLevel", pk_field="_id", pk_type=ObjectId, pk_nullable=0, is_asymmetric=0

Connection[2]: Session[2]: Fetching changeset for upload (client_version=3, server_version=0, changeset_size=26, origin_timestamp=250982881927, origin_file_ident=0)
Connection[2]: Session[2]: Changeset: 3F 00 08 54 6F 70 4C 65 76 65 6C 02 00 0A 63 9A 3F E1 EF B3 CA B5 C6 44 E5 BC
Connection[2]: Session[2]: Changeset (parsed):
InternStrings   0="TopLevel"
CreateObject    path=TopLevel[ObjectId{639a3fe1efb3cab5c644e5bc}]

Connection[2]: Download message compression: is_body_compressed = false, compressed_body_size=0, uncompressed_body_size=0
Connection[2]: Session[2]: Received: DOWNLOAD(download_server_version=3, download_client_version=3, latest_server_version=3, latest_server_version_salt=4386445960811775419, upload_client_version=5, upload_server_version=1, downloadable_bytes=0, last_in_batch=true, query_version=0, num_changesets=0, ...)
Connection[2]: Session[2]: Sending: UPLOAD(progress_client_version=6, progress_server_version=3, locked_server_version=3, num_changesets=0)
Connection[2]: Session[2]: Progress handler called, downloaded = 41, downloadable(total) = 41, uploaded = 49, uploadable = 49, reliable_download_progress = true, snapshot version = 6
Connection[2]: Session[2]: Initiating deactivation
Connection[2]: Session[2]: Sending: UNBIND
Connection[2]: Session[2]: Deactivation completed
Connection[2]: Allowing reconnection in 633 milliseconds
Connection[2]: Disconnected
Connection[2]: Destroying connection object
===============================================================================
All tests passed (11 assertions in 1 test case)

I think it's time to do some pair programming on this with a debugger to try to figure out where the sync session is getting re-activated from. I'm pretty unconvinced that it's simply because realm_begin_write() is being called, but I don't know exactly how the lifetime of all the objects involved work in Kotlin. [~daniel.tabacaru@mongodb.com], could you work with [~eduardo.lopezgutierrez@mongodb.com] on debugging this since you're in the same time zone?

@cmelchior
Copy link
Contributor

We can reproduce this in Kotlin and I isolated it to this place:

image

It looks like freezing a Realm somehow causes it to revive the session, which sounds like the wrong behaviour?

@jbreams
Copy link
Contributor

jbreams commented Dec 19, 2022

I think calling revive_if_needed() when opening a realm has been a long-standing behavior, although @tgoyne changed where we call it in the past few months in #5968. Maybe that change in #5968 is now calling revive_if_needed() in the wrong place or at least when it didn't used to?

@tgoyne
Copy link
Member

tgoyne commented Dec 20, 2022

I think we shouldn't be reviving the user if the Realm we're obtaining is frozen. do_get_realm() knows if it's opening a frozen Realm at the point where it calls revive_if_needed() so this should be simple to do.

Reviving for a live Realm is also a bit weird. We didn't specifically intend for opening a Realm to negate a previous call to suspend(); it's just that suspend() is a hack and doesn't put the sync session in a distinct state. It is long-standing behavior that users could plausibly be relying on, though.

@sync-by-unito
Copy link

sync-by-unito bot commented Jan 4, 2023

➤ Jonathan Reams commented:

Just wanted to update this to say I'm still working on it. I've written a few solutions and kinda hate all of them. Hopefully I'll have a fix I'm happy with this week.

@jbreams jbreams linked a pull request Jan 10, 2023 that will close this issue
3 tasks
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants