B4J Question [ABMaterial][Supabase] Can we use them both?

yiankos1

Well-Known Member
Licensed User
Longtime User
Hello team,

Last month i created a webapp using both of them. Everything working fine in debug and release mode in my pc (localhost:8081). When i upload at my ubuntu VPS, i encounter many errors. Here is a sample code that i use to store personal data to Supabase:
B4X:
Sub btnSave_Clicked(Target As String, SubTarget As String)
 
    page.PauseDelayed(500)

    'I get all data from inputs(edittexts)
    Dim etSurname As ABMInput = page.Component("etSurname")
    Dim etName As ABMInput = page.Component("etName")
    Dim etMail As ABMInput = page.Component("etMail")
    Dim comboSex As ABMCombo = page.Component("comboSex")
    Dim etPhone As ABMInput = page.Component("etPhone")
    Dim etPhoneEme As ABMInput = page.Component("etPhoneEme")
    Dim etTown As ABMInput = page.Component("etTown")
    Dim etPostal As ABMInput = page.Component("etPostal")
    Dim etStreet As ABMInput = page.Component("etStreet")
    Dim etNumber As ABMInput = page.Component("etNumber")
 
    'i create update statement in order to update the correct columns
    Dim Update As Supabase_DatabaseUpdate = Main.xSupabase.Database.UpdateData
    Update.From("users")
    Update.SelectData
    Update.Update(CreateMap("surname":etSurname.Text.Trim,"name":etName.Text.Trim,"email":etMail.Text.Trim, "sex": comboSex.GetActiveItemId, _
                         "town":etTown.Text.Trim,"postal":etPostal.Text.Trim,"street":etStreet.Text.Trim, _
                        "number":etNumber.Text.Trim,"phone":etPhone.Text.Trim,"phone_eme":etPhoneEme.Text.Trim))
    Update.Eq(CreateMap("id":Main.userData.id))
    Wait For (Update.Execute) Complete (Result As SupabaseDatabaseResult)
    If Result.Error.Success Then
  
        For Each Row As Map In Result.Rows
            'If everything with supabase update was ok, I update the "userData" type. (userData is a type where i store all user data in order to access them from all pages)
            Main.userData.surname = Row.Get("surname")
            Main.userData.name = Row.Get("name")
            Main.userData.email = Row.Get("email")
            Main.userData.sex = Row.Get("sex")
            Main.userData.town = Row.Get("town")
            Main.userData.postal = Row.Get("postal")
            Main.userData.street = Row.Get("street")
            Main.userData.number = Row.Get("number")
            Main.userData.phone = Row.Get("phone")
            Main.userData.phone_eme = Row.Get("phone_eme")
      
        Next
  
        page.ShowToast("updateUser","toastgreen","Profile updated!",2000,False)
    Else
        page.ShowToast("updateUser","toastorange",Result.Error.ErrorMessage,2000,False)
    End If
 
    page.Resume
 
End Sub

I get this error:
B4X:
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: Resumable sub already completed
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
    at anywheresoftware.b4j.object.WebSocketModule$Adapter$1.run(WebSocketModule.java:142)
    at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
    at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
    at anywheresoftware.b4j.object.WebSocketModule$Adapter$ThreadHandler.run(WebSocketModule.java:207)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: Resumable sub already completed
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:522)
    at anywheresoftware.b4a.keywords.Common.CallSubNew3(Common.java:476)
    at b4j.example.profile._page_parseevent(profile.java:643)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    ... 10 more
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: Resumable sub already completed
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:513)
    ... 17 more
Caused by: java.lang.RuntimeException: Resumable sub already completed
    at anywheresoftware.b4a.keywords.Common.WaitFor(Common.java:1073)
    at b4j.example.supabase_databaseupdate$ResumableSub_Execute.resume(supabase_databaseupdate.java:118)
    at b4j.example.supabase_databaseupdate._execute(supabase_databaseupdate.java:75)
    at b4j.example.profile$ResumableSub_btnSave_Clicked.resume(profile.java:115)
    at b4j.example.profile._btnsave_clicked(profile.java:41)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    ... 18 more

Wait For throws this error.

Why at local release everything working fine and in VPS not? JDK versions are the same, WWW folder is uploaded, copymewithjar.needs is uploaded.

Moreover, in VPS server i get this error:
B4X:
ResponseError. Reason: , Response: {"message":"No API key found in request","hint":"No `apikey` request header or url param was found."}
But, if i click the same button couple of time and throw me the same error, then supabase update happens! Like magic!

edit: Supabase is initialized in main


******SOLUTION:
Long story short, ABMaterial and Supabase does not work well together. Yuo should switch back in SQL (DBM Class)
 
Last edited:
Solution
Thank you again for all these clarifications. I will try to contact with Alexander tomorrow, if he knows something about this behavior and if it is fixable, or i have to switch to SQL db.
Please note: If you use SQL where you use one user account to connect to the DB and then use queries against user tables to login a user (do not actually log them into their own DB account), then you can use Supabase the same way. Have one account log into Supabase and then use separate user tables to authenticate your users. If you go that route, Supabase should work. The issue here is that Supabase is not really designed to run in a multi-threaded environment with each user having their own Supabase connection. Again, even in an SQL...

OliverA

Expert
Licensed User
Longtime User
But, if i click the same button couple of time and throw me the same error, then supabase update happens! Like magic!
Make sure you're not dealing with some sort of timing issue. Your VPS environment may process your DB/network requests at a different rate. Also make sure that not some sort of network filtering in your VPS environment is hampering you. Also, make sure all the rights are set up correctly (file rights, service rights, group rights, user rights, etc.) are setup correctly. What type of OS/environment is your local development? What type of OS/environment is the VPS?
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
What type of OS/environment is your local development?
Windows 11
What type of OS/environment is the VPS?
Ubuntu 22.04.4 VPS

Thank you very much for your answer. It gives me a way to search.

I would be grateful if you can explain a little more these: "Make sure you're not dealing with some sort of timing issue" & "network filtering"

I think that this behavior with couple-clicking-working is something about timing issue as you mention.
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
"Make sure you're not dealing with some sort of timing issue"
Sometimes your local system's speed can hide issues that may arise if a system (computer/network/etc) is not as fast as your own. Timeouts can occur that would not happen during local testing that can change the dynamics of the running application.

"network filtering"
Sometimes your VPS system is behind a software switch/firewall that you can configure and is defaulted to be very strict in traffic that is allowed.
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
Sometimes your local system's speed can hide issues that may arise if a system (computer/network/etc) is not as fast as your own. Timeouts can occur that would not happen during local testing that can change the dynamics of the running application.


Sometimes your VPS system is behind a software switch/firewall that you can configure and is defaulted to be very strict in traffic that is allowed.
Thank you for your clarification. I will try to dive onto it. I will post my findings.

Btw, if someone managed to get these two working on a VPS or a real environment (not localhost) please inform me.

It's too pitty, after sooo many hours of development to find out that these two does not work together. 😒
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
After searching, i think that "Resumable sub already completed" error comes from line 9 :

B4X:
Sub btnLogin_Clicked(Target As String)
 
    AppPage.PauseDelayed(500)
 
    Dim mymodal As ABMModalSheet = AppPage.ModalSheet("login")
    Dim etEmail As ABMInput = mymodal.Content.Component("etEmail")
    Dim etPass As ABMInput = mymodal.Content.Component("etPass")
 'Sign in user with editetext's email and password
        Wait For (Main.xSupabase.Auth.LogIn_EmailPassword(etEmail.Text.Trim,etPass.Text.Trim)) Complete (User As SupabaseUser)
        If User.Error.Success Then
   
            Log("successfully logged in with " & User.Email)
   'Go to sub getUser, in order to get users personal data
            getUser(User.Id)
 
        Else
            Log("Error: " & User.Error.ErrorMessage)

            AppPage.ShowToast("loginToast","toastorange",User.Error.ErrorMessage,2000,False)
        End If
 
    AppPage.Resume

End Sub
B4X:
Sub getUser(id As String)
 'query in order to get all user's data
    Dim Query As Supabase_DatabaseSelect = Main.xSupabase.Database.SelectData
    Query.Columns("users(*),id_role,gym_roles(name,level),gyms(name)").From("gym_users").Filter_Equal(CreateMap("id_user":id))
    Wait For (Query.Execute) Complete (DatabaseResult As SupabaseDatabaseResult)
    If DatabaseResult.Error.Success Then
        For Each Row As Map In DatabaseResult.Rows
   
            AppPage.ShowToast("loginToast","toastgreen","Connected!",2000,False)
   
            ABMShared.NavigateToPage(ws, "", "./" & InitialPage)
            Log("successfully got user")
        Next
    Else
        AppPage.ShowToast("addUserAppointment","toastorange",DatabaseResult.Error.ErrorMessage,2000,False)
    End If

End Sub
because both resumable subs has "Complete" event.

So my question is, how should i treat webapps - websockets with these resumable quering database subs? What do i have to do with async queries? Do i have to user CallSubDelayed, CallSub, StartMessageLoop, StopMessageLoop.

It is an ABMaterial project with jServer, but i am not sure if it's considered as an UI or non-UI webapp.

Any help is appreciated to find a way out.

EDIT: I found a similar post about the same error, that is about threading
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
because both resumable subs has "Complete" event.
That does not matter. You can have multiple Wait For's with Complete and (if the underlying code used with the wait for is implemented properly) B4X will properly call the appropriate version of Complete

So my question is, how should i treat webapps - websockets with these resumable quering database subs? What do i have to do with async queries? Do i have to user CallSubDelayed, CallSub, StartMessageLoop, StopMessageLoop.
WebSockets have an event queue, so you have to do nothing

It is an ABMaterial project with jServer, but i am not sure if it's considered as an UI or non-UI webapp.
Non-UI

Any help is appreciated to find a way out.

EDIT: I found a similar post about the same error, that is about threading
There may be an issue in Supabase, where it does not respond to the appropriate thread (since each WebSocket connection runs on its own thread). Many people here have implemented ABM solutions with a database backend (most likely via B4X's SQL library) without running into any such issues. Therefore, the likely culprit is Supabase itself.
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
Therefore, the likely culprit is Supabase itself
Thank you again for all these clarifications. I will try to contact with Alexander tomorrow, if he knows something about this behavior and if it is fixable, or i have to switch to SQL db.
 
Upvote 0

Alexander Stolte

Expert
Licensed User
Longtime User
I will try to contact with Alexander tomorrow, if he knows something about this behavior and if it is fixable
I have no idea, I only offer the library. Sorry.
The lib. works on B4A, B4I and B4J (Desktop and non ui).
Then it does not work with AB material.
 
Upvote 0

MichalK73

Well-Known Member
Licensed User
Longtime User
Btw, if someone managed to get these two working on a VPS or a real environment (not localhost) please inform me.
That's what you mean?
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
That's what you mean?
Thank you for your response. No, webapp works perfectly on a VPS. The issue arises using both ABMaterial and Supabase on a VPS. After reading couple of posts, I assume it's a threading issue.
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
I have no idea, I only offer the library. Sorry.
The lib. works on B4A, B4I and B4J (Desktop and non ui).
Then it does not work with AB material.
I understand and thank you for your response. Wish you a great day. If I find a solution I will let you know
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
@OliverA had contacted me and discovered a bug in the b4xlib which could possibly cause the problem. Attached is a B4XLib that no longer contains this bug, please test if your bug still occurs with the new version.
Firstly i would like to thank you both, wasting your time fixing my problem.

I tried your updated version at my VPS, but with no luck again. Again the same errors (resumable and No API key)

So, i decided to upload my project at my work's VPS which is more powerful.
"Resumable sub already completed" keeps throwing, not as many times as my VPS though.
The other error "No API key found in request" does not shown.

That is my last day trying to find a reason behind these errors. After that, i have to move on!

Thank you all, one more time!
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
So, i decided to upload my project at my work's VPS which is more powerful.
"Resumable sub already completed" keeps throwing, not as many times as my VPS though.
The other error "No API key found in request" does not shown.

That is my last day trying to find a reason behind these errors. After that, i have to move on!
I would like to test something.
I think I now know what is going on. Supabase is a per user object. So, in your ABM application, each Login requires its own Supabase instantiation, not the one used in Main. Each time you call
Wait For (Main.xSupabase.Auth.LogIn_EmailPassword(etEmail.Text.Trim,etPass.Text.Trim)) Complete (User As SupabaseUser)
you clobber the other user's login information that is stored in xSupabase.Auth. So don't use Main.xSupabase, but initialize a new Supabase with each ABM login page and associate that Supabase object with that user (and only use it for that user).
 
Upvote 0

Alexander Stolte

Expert
Licensed User
Longtime User
Each execute queries the auth class to check whether the access token is still valid and the whole thing uses a wait for, I have left this query out of the "update" and it seems to work. So there may be something to your theory.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Thank you again for all these clarifications. I will try to contact with Alexander tomorrow, if he knows something about this behavior and if it is fixable, or i have to switch to SQL db.
Please note: If you use SQL where you use one user account to connect to the DB and then use queries against user tables to login a user (do not actually log them into their own DB account), then you can use Supabase the same way. Have one account log into Supabase and then use separate user tables to authenticate your users. If you go that route, Supabase should work. The issue here is that Supabase is not really designed to run in a multi-threaded environment with each user having their own Supabase connection. Again, even in an SQL environmnet, the (seemingly) standard way to use them in a web-app application is to use one account for the DB, with the web-app checking user access against tables that are accessible via that one account. For that type of DB setup, Supabase should be suitable as a backend for web-apps.
 
Upvote 0
Solution

OliverA

Expert
Licensed User
Longtime User
Please note:
In the end, looking at Supabase's site (https://supabase.com/), having user management is part of the package. So even though what I'm proposing above may work, it may be counter-intuitive on how Supabase works. I'll have to mull over this a little bit more.
access token
I think this is the key here. Currently the access token is stored locally, but I think in a web-environment it should be stored as a cookie at the client site. Each cookie (auth token) would then be different for each user. If they come back later to the ABM site, the cookie can be checked and the auth token can be validated. If expired, a user has to log in once more. Or something like that.
 
Upvote 0
Top