Skip to content

UPDATE in transaction is not applied sometimes #167

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

Open
Radiokot opened this issue Apr 13, 2025 · 5 comments
Open

UPDATE in transaction is not applied sometimes #167

Radiokot opened this issue Apr 13, 2025 · 5 comments

Comments

@Radiokot
Copy link

Radiokot commented Apr 13, 2025

Hi guys, I have this weird issue with 1.0.0-BETA28, and I would greatly appreciate any help in debugging it.

Scenario:

  • An expense logging screen of an Android app is opened via a desktop shortcut
  • User selects account and enters the amount
  • A writeTransaction is executed in viewModelScope which contains the following queries:
    • INSERT new row into the transfers table
    • SELECT current account balance from the accounts table (stored as TEXT and mapped into BigInteger)
    • UPDATE the accounts table, set corresponding account balance to current - transfer amount
  • Once writeTransaction is completed successfully, the screen closes and so the app goes to background

The issue: sometimes the balance UPDATE is not applied, although the new row gets inserted into the transfers table within the same transaction.

On the other hand, if the same expense logging is done from the main app screen, so the app doesn't go to background on transaction success, the UPDATE is always applied, and the user immediately sees the updated value in the UI (via database.watch())

Here is the log for the case when UPDATE has not been applied:

log.txt

There's a big time difference between 21:43:11.616 and 21:43:27.738 because I actually managed to suspend the SupabaseConnector by a breakpoint to confirm that table.update was indeed called with entry.opData having "balance=-4314082". Nevertheless, the balance in Supabase remained the same, and so it did in the app.

@simolus3
Copy link
Contributor

Thanks for the report! In the logs, I see a number of SELECT id, tx_id, data FROM ps_crud ORDER BY id ASC LIMIT 1 calls indicating that you might be calling getCrudBatch with a limit of 1. Is this intentional? It splits up the transaction you had locally into separate supabase uploads which breaks the atomicity of the transaction. I'm not sure yet how that causes the issue of the update being lost, but it's still something that stands out.

@Radiokot
Copy link
Author

I do not control this limit, I connect my PowerSyncDatabase with SupabaseConnector, pretty standard 🤔

@simolus3
Copy link
Contributor

Oh right, sorry 🤦 And that one actually uses the default limit, so I need to check where that LIMIT 1 is coming from.

@Radiokot
Copy link
Author

Radiokot commented Apr 14, 2025

Is it this one?

transaction.getAll("SELECT id, tx_id, data FROM ps_crud ORDER BY id ASC LIMIT 1") {

Image

@Radiokot
Copy link
Author

Radiokot commented Apr 16, 2025

Hi @simolus3, I have new findings to share:

  1. If I swap transfers INSERT and accounts UPDATE, so the update is executed first, then the update result is always preserved, and the transfer gets inserted locally as well!
  2. However, when it immediately tries to sync the changes to Supabase when the app is already in background, the transfers INSERT (POST) sometimes gets rejected because of RLS policy violation. Why? Because for this operation for some reason an anon role JWT is used, despite my PowerSyncDatabase gets connected with SupabaseConnector upon creation. When I then open the app later and the sync restarts, the INSERT eventually gets synced.

So, weird stuff.

Here you can see attempts to sync transfers INSERT with anon role JWT:

11:14:47.146 <no-tag>                        E  Data upload error - retrying last entry: CrudEntry<40/92 PUT transfers/24678427-d3a8-43a7-8035-875d4b42242c {destination_amount=10000000, destination_id=96878196-f8fe-37db-8dd1-ad5ccd762087, source_amount=10000000, source_id=0733cd73-712b-345c-8358-31c04674c73a, time=2025-04-15T21:00:02Z}>, io.github.jan.supabase.postgrest.exception.PostgrestRestException: new row violates row-level security policy for table "transfers"
                                                URL: https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
                                                Headers: [Authorization=[Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJyYnVlenZidGticm9meXBvd2p6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwMjAwNjcsImV4cCI6MjA1NDU5NjA2N30.lmQmzRNj1b-ZfAc1YlU7gGBgKS_e706ioTU0jxxyG9A], Prefer=[return=minimal,resolution=merge-duplicates], Content-Profile=[public], apikey=[eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJyYnVlenZidGticm9meXBvd2p6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwMjAwNjcsImV4cCI6MjA1NDU5NjA2N30.lmQmzRNj1b-ZfAc1YlU7gGBgKS_e706ioTU0jxxyG9A], X-Client-Info=[supabase-kt/3.1.4], Accept=[application/json], Accept-Charset=[UTF-8]]
                                                Http Method: POST
11:14:47.146 <no-tag>                        E  PowerSyncException: new row violates row-level security policy for table "transfers"
                                                URL: https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
                                                Headers: [Authorization=[Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJyYnVlenZidGticm9meXBvd2p6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwMjAwNjcsImV4cCI6MjA1NDU5NjA2N30.lmQmzRNj1b-ZfAc1YlU7gGBgKS_e706ioTU0jxxyG9A], Prefer=[return=minimal,resolution=merge-duplicates], Content-Profile=[public], apikey=[eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJyYnVlenZidGticm9meXBvd2p6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwMjAwNjcsImV4cCI6MjA1NDU5NjA2N30.lmQmzRNj1b-ZfAc1YlU7gGBgKS_e706ioTU0jxxyG9A], X-Client-Info=[supabase-kt/3.1.4], Accept=[application/json], Accept-Charset=[UTF-8]]
                                                Http Method: POST
11:14:47.147 <no-tag>                        E  Error uploading crud: new row violates row-level security policy for table "transfers"
                                                URL: https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
                                                Headers: [Authorization=[Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJyYnVlenZidGticm9meXBvd2p6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwMjAwNjcsImV4cCI6MjA1NDU5NjA2N30.lmQmzRNj1b-ZfAc1YlU7gGBgKS_e706ioTU0jxxyG9A], Prefer=[return=minimal,resolution=merge-duplicates], Content-Profile=[public], apikey=[eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJyYnVlenZidGticm9meXBvd2p6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwMjAwNjcsImV4cCI6MjA1NDU5NjA2N30.lmQmzRNj1b-ZfAc1YlU7gGBgKS_e706ioTU0jxxyG9A], X-Client-Info=[supabase-kt/3.1.4], Accept=[application/json], Accept-Charset=[UTF-8]]
                                                Http Method: POST
11:15:23.523 <no-tag>                        E  Error in streamingSync: Software caused connection abort

But after I manually opened the app in a minute, the same INSERT is synced successfully:

11:15:47.990 Supabase-Core                   D  Starting POST request to endpoint /rest/v1/transfers
11:15:47.996 4MN:DefaultRequest              V  Applied DefaultRequest to https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid. New url: https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
11:15:47.996 4MN:ContentNegotiation          V  Adding Accept=application/json header for https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
11:15:48.000 4MN:ContentNegotiation          V  Converted request body using io.ktor.serialization.kotlinx.KotlinxSerializationConverter@72a1da7 for https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
11:15:48.000 4MN:HttpPlainText               V  Adding Accept-Charset=UTF-8 to https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
11:15:48.001 4MN:defaultTransformers         V  Transformed with default transformers request body for https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid from class io.ktor.http.content.TextContent
11:15:48.082 TrafficStats                    D  tagSocket(154) with statsTag=0xffffffff, statsUid=-1
11:15:48.310 4MN:HttpCallValidator           V  Validating response for request https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
11:15:48.310 4MN:DefaultResponseValidation   V  Skipping default response validation for https://brbuezvbtkbrofypowjz.supabase.co/rest/v1/transfers?columns=destination_amount%2Cdestination_id%2Csource_amount%2Csource_id%2Ctime%2Cid
11:15:48.318 Supabase-Core                   D  POST request to endpoint /rest/v1/transfers successfully finished in 295ms

Radiokot added a commit to Radiokot/4money that referenced this issue Apr 16, 2025
Fix (presumably) not saving updated balance from time to time when
launched from the transfer shortcut.

powersync-ja/powersync-kotlin#167
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants