Expensify / App

Welcome to New Expensify: a complete re-imagination of financial collaboration, centered around chat. Help us build the next generation of Expensify by sharing feedback and contributing to the code.
https://new.expensify.com
MIT License
3.34k stars 2.77k forks source link

Ensure we call ReconnectApp when the passed clientUpdateID is not in the DB #47582

Open iwiznia opened 1 month ago

iwiznia commented 1 month ago

Context https://expensify.slack.com/archives/C03TQ48KC/p1723832372007299?thread_ts=1723826918.927409&cid=C03TQ48KC

Problem

Right now when the clientUpdateID is not in the DB because it got deleted already, we are just assuming you are up to date, but we really can't know that, there might be updates that you missed.

Solution

If we don't have the clientUpdateID in the DB we should instruct the client to call ReconnectApp to ensure they get all the data they might have missed

melvin-bot[bot] commented 1 month ago

Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

melvin-bot[bot] commented 3 weeks ago

@iwiznia Whoops! This issue is 2 days overdue. Let's get this updated quick!

melvin-bot[bot] commented 3 weeks ago

@iwiznia 6 days overdue. This is scarier than being forced to listen to Vogon poetry!

iwiznia commented 2 weeks ago

Need to update all overdue issues and then will work on this

iwiznia commented 2 weeks ago

ok writing down the solution here:

  1. In auth, we will pass clientUpdateID to getPreviousUpdateID here
  2. At the beginning of getPreviousUpdateID we will check if clientUpdateID is in the DB, if it is not we will return -1
  3. In Auth class here if the response has accounts.X.lastUpdateID and previousUpdateID is -1, we will call AppInit::reconnectApp without $updateIDFrom
  4. This is the part that's unclear... we basically need to add them to the response, but not send them via pusher nor save them in the DB (so we don't want to call Push_API::queue) we basically want to include them in Onyx::getAccountOnyxUpdates so that they get added to the response here, so maybe we can convert the data to events and add them directly to Pusher_API::$sentEvents (which is what Onyx::getAccountOnyxUpdates uses). I think this should work, even if it is a little unconventional (because we did not actually sent the events)
  5. We would also save the fact we called ReconnectApp in a class variable in the Auth class and skip the behavior on step 3 by checking this variable

Thoughts? @danieldoglas

danieldoglas commented 2 weeks ago

I'm OK with this logic, we only want to add the ReconnectApp for the caller.

IF we're doing it to async onyx updates, then I think we might need to send something that says "you should call reconnectApp from scratch"

Maybe it's time to introduce new custom actions we can send to the app?

iwiznia commented 1 week ago

IF we're doing it to async onyx updates,

We are not, since we don't have a clientUpdateID there

danieldoglas commented 1 week ago

how are we dealing with cases where we can't find a previousUpdateID (so no updates at all for them) for an account that is receiving an async update?

iwiznia commented 1 week ago

Yesterday I thought about it and thought it was a non issue, but I don't know how I convinced myself of that 😂

I think there's 2 scenarios, both of them happen when we are in the GetMissingOnyxMessages flow:

  1. We find a previousUpdateID for you. I think there's no issue here. When you receive it either you apply it or if you don't have the previousUpdateID, call GetMissingOnyxMessages which will either download the missing updates or do a full reconnect if we don't have them
  2. We don't find a previousUpdateID and thus return -1. In this case we would have to run the same logic described in step 4 but with the main difference that we would need to track if we run that logic for each user in that same class. We would do that here

Does that make sense?

danieldoglas commented 1 week ago

I don't think that's the best solution. That means we would send possibly sereal megabytes of updates through pusher for those users that do not have the previous updateID

I'd say we'd need to create a new type of onyx operation, something like reload, and send that operation with the update that is being sent. If they receive that operation, then we do a OpenApp in the app to reload everything.

iwiznia commented 1 week ago

Good point! That makes total sense, a ReconnectApp call can be huge and the users might not even have the app/web open.

But if we do that, wouldn't it make more sense to use that same onyx operation for the current user and simplify this whole thing? I think it would, because that way we would only have one way of handling this for both cases. Also while we could do what I described above for the current user and avoid the extra network roundtrip, this flow is basically the same as you are missing updates and need to do another call that we already have.

iwiznia commented 1 week ago

I just realized that a new onyx operation is not the right call. Calling an API command to do a full reconnect is not an onyx operation at all. Instead, we can use a new pusher event. Summarizing the updated solution that solves the problem for both current user and others:

  1. In auth, we will pass clientUpdateID to getPreviousUpdateID here
  2. At the beginning of getPreviousUpdateID we will check if clientUpdateID is in the DB, if it is not we will return 0 (same as we do when we find no updates)
  3. In Auth class here if the response has accounts.X.lastUpdateID and previousUpdateID is 0, we will queue pusher event appReload ensuring we set the event's pusherSocketID to 0 (this is so that the event is delivered to the user making the request and is not instead included in the response)
  4. We would also save the fact we queued this update in a class variable in the Auth class so we can avoid sending 2 events to the same user
  5. In app, we will subscribe to this new event like we do here
  6. And call App action reconnectApp
danieldoglas commented 1 week ago

I think this makes sense. I'm just not fully sold on adding a new event/event subscription.

danieldoglas commented 1 week ago

After talking to ioni, I agree we can create a new event.

melvin-bot[bot] commented 1 week ago

@iwiznia, @danieldoglas Whoops! This issue is 2 days overdue. Let's get this updated quick!

iwiznia commented 1 week ago

Working on this. I have the PRs ready above. I need to test the other users case.

iwiznia commented 1 week ago

Sent all PRs for review