Closed redjonzaci closed 8 months ago
It's hard to reproduce since it's so integrated at our system, but let me know what would you need to help us solve this issue or decide that it's not a DataStore issue.
Can you show us the relevant code and/or cypress tests?
FWIW, we use cypress for our e2e tests and have found it to be a bit flaky. We often have to throw indicators on the screen for DataStore readiness for cypress to watch and react to. Other strategies we've used are to watch for Hub events and only begin executing relevant test code after key mutations leave the outbox, for example. But, we can hopefully provide better guidance seeing some sample code.
Maybe this description helps:
We have a Step Functions state machine that runs multiple Lambda functions in parallel that produce Create Mutations in AppSync. In our current scenario, 4 Lambda functions produce 1-4 Create Mutations, in total 11.
We then notice that IndexedDB gets 11 records, but observeQuery
sometimes doesn't observe all or observes none.
We could look at the issue on a call or allow you to look at logs.
We could also try to reproduce the issue, but this would take longer.
We use observeQuery
in the application code, not in the Cypress code, so we can't post any of it.
Let me know if I can do anything else to help.
Also, would it be possible to share some of the e2e strategies/examples you use in your tests?
Any update on this? This would really help us move forward with testing critical features of our app.
Also, would it be possible to share some of the e2e strategies/examples you use in your tests?
We don't do much beyond what I noted above. You can take a look at the DataStore events page and see ready
and outboxStatus
in particular. To test some paths, we'll occasionally set a node on page to show a generic "ready: no" message before DataStore starts and/or when a record is saved, and we'll change status to "ready: yes" when those events come in.
But, this doesn't even remove all the flakiness. Cypress testing has generally been flaky for us. We have pretty well-decomposed sample apps and test scripts with 3 retries in our pipeline for each test script. This seems to bring the success rate up quite a bit.
The problem is that sometimes observe/observeQuery doesn't get all 11 objects from the IndexedDB.
What's the rate of failure here? Would retries help?
Regarding the backend processing stuff, more info is generally helpful. But the backend stuff sounds OK in this case, since you see you're seeing the items populate in IndexedDB locally. If that's the case, observeQuery
should pick them up as long as your test timing/synchronization is right and your predicates are OK — unless there's a bug or package installation issue, which brings me to the next point ...
There is one thing I didn't notice initially.
@aws-amplify/datastore: ^4.2.1 => 4.3.0
aws-amplify: 5.2.2 => 5.2.2
@aws-amplify/cli: 12.0.0
aws-amplify
already includes DataStore. You're potentially installing it twice, which can lead to very spooky behavior.Before anything else, I'd do those udpates to be sure.
We use observeQuery in the application code, not in the Cypress code, so we can't post any of it.
If the package updates don't help, I think we're at a point where we need more detailed repro steps in order to make progress. (E.g., a model + code that demonstrates the issue.)
@svidgen thanks a lot for the very elaborate answer, we are trying your suggestions and will let you know!
@redjonzaci - how did @svidgen's suggestions work for you? Thanks!
@david-mcafee we're still working on it, can we keep this open and I will let you know when we don't need any more help?
@redjonzaci - how did @svidgen's suggestions work for you? Thanks!
Hi, I work on the same team with Redjon.
So far we have found one issue with amplify Datastore, the toArray()
function returns stale deleted data when called again on the same reference of an object:
ex:
let comments = await post.comments.toArray();
comments.forEacht(c => Datastore.delete(c));
comments = await post.comments.toArray(); // returns the same thing as previously
Let me know if I should create a separate issue.
We have done some testing that is showing that removing belongsTo
relationships makes things pass more often (9/10 times) compared to (2/10) times when the belongsTo relationship is present. However we do need the relationship defined for other parts of the application to work properly, so we can't really remove them without breaking other parts of the app. We have not been able to reproduce it in a small project with a minimal schema since maybe that is too "simple", we could get on a call and try to show you guys in private, sadly we can't share the code/logs here.
@redjonzaci - Absolutely! We'll keep this ticket open until we've heard back from you.
@djorgji - Lazily loaded properties are memoized to align more with the immutable nature of our model instances. i.e. once you look at an instance's properties, they will not change. In order to get the most up-to-date values for the parent model, I would do one of the following:
Additionally, I did want to point out that for the following code snippet you included, I wouldn't expect the children to be finished deleting after this:
comments.forEacht(c => Datastore.delete(c));
Even if you were to add an await
inside the forEach
, that does not imply an await
outside the loop. Instead, you would want to map into a Promise.all()
:
await Promise.all(children?.map(async (o) => await DataStore.delete(o)));
@redjonzaci - Absolutely! We'll keep this ticket open until we've heard back from you.
@djorgji - Lazily loaded properties are memoized to align more with the immutable nature of our model instances. i.e. once you look at an instance's properties, they will not change. In order to get the most up-to-date values for the parent model, I would do one of the following:
- Utilize a DataStore subscription to keep the parent model up-to-date
- Re-query the parent after you have deleted the children to get the latest values
- Use a nested query predicate with the child model ("Option 3" under the Querying Relations docs). Note that when using this approach the children will not be lazily loaded, and thus will be up-to-date.
We ended up just doing a separate query, If this intended then it is not mentioned in the documentation, or I am missing it.
Additionally, I did want to point out that for the following code snippet you included, I wouldn't expect the children to be finished deleting after this:
comments.forEacht(c => Datastore.delete(c));
Even if you were to add an
await
inside theforEach
, that does not imply anawait
outside the loop. Instead, you would want to map into aPromise.all()
:await Promise.all(children?.map(async (o) => await DataStore.delete(o)));
Sorry about that, I did omit the await in the snippet above, we were utilizing a
promise.all
, but letting all the promises to run at the same time.
Here is the weird part, the observeQuery
is being triggered properly when we utilize delete via model, or predicate (can't do this because of https://github.com/aws-amplify/amplify-js/issues/11600).
Promise.all(comments.map((comment) => DataStore.delete(comment)));
// or
await DataStore.delete(Comment, (c) => c.postID.eq(post.id));
// but not when we use the identity...
Promise.all(ids.map((id) => DataStore.delete(id));
We are still stuck on updates originating from AppSync not reliably triggering observeQuery
, we are investigating that still.
@djorgji - can you provide additional reproduction steps regarding the issue you're seeing with observeQuery
? Thank you!
Hi 👋 Closing this as we have not heard back from you. If you are still experiencing this issue and in need of assistance, please feel free to comment and provide us with any information previously requested by our team members so we can re-open this issue and be better able to assist you.
Thank you!
Before opening, please confirm:
JavaScript Framework
React
Amplify APIs
GraphQL API, DataStore
Amplify Categories
api
Environment information
Describe the bug
Whenever an object is created via the GraphQL API, the WebSocket picks it up. So in my case, every time I do an operation, 11 objects are created and picked up by the WebSocket and stored in IndexedDB. The problem is that sometimes
observe
/observeQuery
doesn't get all 11 objects from the IndexedDB. This mostly happens when Cypress testing, but there are few times it happens when I do the operation manually in the app outside of Cypress.What do you think might be causing it?
Expected behavior
observe
/observeQuery
gets every item from IndexedDB.Reproduction steps
It happens when I am Cypress testing.
Code Snippet
No response
Log output
No response
aws-exports.js
No response
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response