Closed Umar009 closed 9 months ago
waiting for response
@Umar009 Our team is prioritizing and will try to look into the issue.
Hi @Umar009,
I was able to reproduce the issue. I called DataStore.start to establish the subscriptions, and then put the iOS app in the background. Then I performed a create mutation followed by a delete mutation, while the app still in the background. ie.
mutation MyMutation {
createTodo(input: {content: "From AppSync Console"}) {
updatedAt
owner
id
createdAt
content
_version
_lastChangedAt
_deleted
}
}
mutation MyMutation2 {
deleteTodo(input: {_version: 1, id: "e097e308-490f-4480-aba6-bcaf6dd41eec"}) {
_deleted
_lastChangedAt
_version
content
createdAt
id
owner
updatedAt
}
}
Once I bring the app back to the foreground, I can see both events, one for the onCreate subscription and one for the onDelete subscription:
[StarscreamAdapter] websocketDidReceiveMessage: - {"id":"B016C8B9-7D7E-4E0E-9191-7B019C7E73A2","type":"data","payload":{"data":{"onCreateTodo":{"id":"e097e308-490f-4480-aba6-bcaf6dd41eec","content":"From AppSync Console","createdAt":"2023-08-09T15:43:00.643Z","updatedAt":"2023-08-09T15:43:00.643Z","__typename":"Todo","_version":1,"_deleted":null,"_lastChangedAt":1691595780670,"owner":"username"}}}}
[StarscreamAdapter] websocketDidReceiveMessage: - {"id":"3FD67560-3755-45A0-926A-3B1CF3A11662","type":"data","payload":{"data":{"onDeleteTodo":{"id":"e097e308-490f-4480-aba6-bcaf6dd41eec","content":"From AppSync Console","createdAt":"2023-08-09T15:43:00.643Z","updatedAt":"2023-08-09T15:43:00.643Z","__typename":"Todo","_version":2,"_deleted":true,"_lastChangedAt":1691595790277,"owner":"username"}}}}
I've attached the remaining logs for a reference. logs2982.log
It appears the DataStoreReconcileAndLocalSaveOperation is started with the version 1 object, and ends up inserting it into the database, while the delete event is not removing the version 1 object.
The unexpected behavior I can see is in IncomingAsyncSubscriptionEventToAnyModelMapper. If two events comes in, and Subscribers.Demand of max(1)
is not returned before another event is emitted, i suspect it's not receiving this second event. There should be two dispose(of graphQLResponse)
prints, but I only see one in the logs
It looks like I am able to reproduce the behavior in a small smaple in https://gist.github.com/lawmicha/e13a7d1100ccbb618c0f86b58e93c184
Emitting value 0
Control Demand 0
Received 0
Emitting value 1
Emitting value 2
Emitting value 4
Emitting value 3
Control Demand 1
Received 1
I'm emitting the values 0 to 4 (like the subscription create and delete events). the intermediate subscriber controls the demand to receive one at a time, before reemitting it. It looks like it's due to the publisher emitting events faster than the subscriber can handle them. I can explore changing this code to perhaps use a buffer operator instead and see if it will fix the problem. Even if this problem is fixed, we can't guaranteed that the events that were sent from the server are processed by the app while it's in the background. Once the websocket connetion is closed, DataStore will eventually catch up through the delta sync process.
@Umar009 One thing you can try in the meantime is to see if you can hook into the app lifecycle methods when it goes into foreground, or in did become active:
func applicationDidBecomeActive(_ application: UIApplication) {
print("application did become active")
Task {
try? await Amplify.DataStore.stop()
try? await Amplify.DataStore.start()
}
}
Calling stop then start will cause it to re-establish the subscriptions and more importantly perform the sync query calls to catch up the data. The deleted record should be in the sync query response, and will reconcile and remove the local model.
We are observing very similar issue but it is not related to deletion but rather updating an objects and it does not happen when app is in the background but is fully in foreground.
Sample case:
Our team is still investigating the issue. We will provide an update as soon as we have more information.
@fzy-spyro and @Umar009 A fix has been released in https://github.com/aws-amplify/amplify-swift/releases/tag/2.26.2 ..
Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.
Describe the bug
We integrated Amplify into our project for Android, iOS, and the web portal. We use Amplify for user sign-in and to store user data. However, we encountered an issue with the iOS app. While it works perfectly fine when iOS App is in active state, creating, deleting, or editing user item entries from the web or Android app get updated real time in iOS App, there is a problem when the iOS app is in the background or closed. Specifically, when a user creates a new entry and then deletes it while the app is in the background or closed, upon opening the app either from the background or a fresh launch, the create event is triggered, but the delete event is not called. Interestingly, if a user edits an item, the event for the edit is called. It's important to note that if an item is already added, and then the app is moved to the background and the device screen is locked, deleting that item from the web portal or Android app will trigger the delete event when the iOS app comes back from the background.
Steps To Reproduce
Expected behavior
Delete event must be triggered on amplify and item must be deleted from Amplify data store
Amplify Framework Version
1.22.2
Amplify Categories
DataStore
Dependency manager
Cocoapods
Swift version
5
CLI version
10.7.3
Xcode version
14.2
Relevant log output