B4J Question Better use CallSub or CallSubDelayed in server application for websocket?

mauro vicamini

Active Member
Licensed User
Longtime User
Hello Everyone,
I'm developping a server application that use websocket, where typically I store each object of the websoket class in a map initialized as a ThreadSafeMap.
When I need to call a client method I iterate through the map objects and I call the sub of the websocket class that call the ws.RunFunction method

B4X:
' in the Main
Sub Process_Globals
    Public mapConnection As Map
    Public srv As Server
    Public tmrSeconds As Timer
End Sub

Sub AppStart (Args() As String)

    srv.Initialize("objServer")
    srv.AddWebSocket("/ws","WebsocketConnection")
    srv.Port = 51042
    srv.Start
    mapConnection = srv.CreateThreadSafeMap
    tmrSeconds.Initialize("tmrSeconds",1000)
    tmrSeconds.Enabled = True
    StartMessageLoop
End Sub

Sub tmrSecondi_Tick
   dim payload as String
   tmrSeconds.Enabled = False
   payload = "somthing to trasmit retrived by a function";
   For Each c As WebsocketConnection In mapConnection.Values
       CallSub2(c,"send",payload)
   next
   tmrSeconds.Enabled = True
End Sub

' in the WebsocketConnection class '

Sub Class_Globals
    Private ws As WebSocket

End Sub

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    ws = WebSocket1
    Main.mapConnection.Put(ws.UpgradeRequest.GetParameter("client_uuid"),Me)
End Sub

Public Sub send(payload As String)
    ws.RunFunction("recive_payload",Array As String(payload))
    ws.Flush
End Sub


Here is my question: for a better performance is it better to call CallSub2(c,"send",payload) or CallSubDelayed2(c,"send",payload) assuming an high number of clients connected on different type of internet connections (lan,mobile,etc..) with different speeds and latencies ?

Thanks for the attention
 

mauro vicamini

Active Member
Licensed User
Longtime User
Why not directly c.send(payload) ?

https://www.b4x.com/android/forum/threads/webapp-chatroom-threads-sessions-and-server-events.39969/

paragraph "Threads" but also the following ones.
But in the chatroom example the call to the websocket class method from the static module is done by CallSubDelayed and not directly from the object method like suggest.
As write in the #4 post "If you call CallSubDelayed then the target thread will be used to execute the code ", so if I call the method of the WebsocketClass with CallSubDelayed from my static Main Module then I think the method is executed in the thread of WebsocketClass.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Yes, in the past I had thought about it; using CallSubDelayed the execution happens in the thread related to the instance of the class that manages the websocket but... normally it is a matter of sending data (strings) so I don't see much convenience. It would be different if calculations were made in that class.
 
Upvote 0

mauro vicamini

Active Member
Licensed User
Longtime User
Thanks Erel,
and if then I need to call a method of the main thread from inside the Websocket Class, it's better to use CallSub or CallSubDelayed?
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Why do you need to do such thing?

Since Mauro is not online at the moment and I'm interested in the topic, I try to "answer for him".

You could only use the server as such, i.e. as a data provider. In this case, the processing should be done on the clients but in some (many) cases this is not good (especially because a hacker could modify the client code).

When, on the other hand, most of the processing takes place on the server, it is not possible to find a way to exploit the "websocket threads" by "delegating" the processing to them (or in any case I could not find the best solution for this).

If you delegate the processing to the "websocket threads" then it is difficult or perhaps impossible that you are able to manage well processing sequences that concern a group of clients (websockets).

Difficult to explain, I hope it is enough.
 
Upvote 0

mauro vicamini

Active Member
Licensed User
Longtime User
I need to call a method in the main thread from websocket class because I need to return some choices from the client and retrasmit this choices to all the clients to show what the other have choose. The application it's a quiz platform: the clients recive a question, they answer and after some seconds they see which is the correct answer and what the other clients had answered. So I need to collect the answer also for compile the ranking that is also trasmited to all the clients at the end of the quiz and record the answers in a database.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
I need to call a method in the main thread from websocket class because I need to return some choices from the client and retrasmit this choices to all the clients to show what the other have choose. The application it's a quiz platform: the clients recive a question, they answer and after some seconds they see which is the correct answer and what the other clients had answered. So I need to collect the answer also for compile the ranking that is also trasmited to all the clients at the end of the quiz and record the answers in a database.
More generally, you need a centralized processing that concerns N clients, therefore you cannot make this processing performed in the "websocket threads".

I too would have liked to take advantage of the threads but it doesn't seem possible to me.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
In the send method of your WebSocket Handler, you could store the packet in an SQL (SQLite) db/threadsafe map. In your timer tick method in main you could then retrieve all new entries and distribute them to the clients. See the push example of the web server examples.

Edit: Have the workflow wrong.

I too would have liked to take advantage of the threads but it doesn't seem possible to me.
Create a background worker. Store the information gathered by the WebSocket handlers in a DB (or in a threadsafe map) and have the background worker process the information. The background worker (or workers) will run in another thread.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Create a background worker. Store the information gathered by the WebSocket handlers in a DB (or in a threadsafe map) and have the background worker process the information. The background worker (or workers) will run in another thread.
I have to think about this; I could have a background worker for each "group" of clients and so a single "place" where the (group) data is processed, in its thread.

Initially, having known that I could execute code in the websocket threads, I was hoping I could do it but there were problems - I don't remember now, I should be thinking deeply ? or going to look at the project.
Your solution may be somewhere in between, don't force the main thread process everything, and not even every websocket thread.

I'll have to find out what the problem was, first; in the end I decided to run everything in the main thread, although I didn't like it very much.

Thank you, @OliverA
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I could have a background worker for each "group" of clients and so a single "place" where the (group) data is processed, in its thread.
Just remember that the number of background workers are static for a running instance of jServer. So if you need to change the number of background workers, you need to stop the server, create your background workers and then start your server.
Your solution may be somewhere in between, don't force the main thread process everything, and not even every websocket thread.
It is.
I'll have to find out what the problem was, first; in the end I decided to run everything in the main thread, although I didn't like it very much.
Yes. The async solutions that are provided by/included in the B4X environment are very efficient and adding extra layers (via threading) often does not produce a noticeable gain in amount of information processed. When using jServer and not having the processing happen on the main thread can help with error handling. If you kill the Main thread, jServer may still run, but it cannot (within itself) be restarted again. Having the processing on a background worker and monitoring it for issues at least gives one the option to restart the server from within the same application. Plus one could create a pool of background workers and use one at a time for processing. Each time something goes bonkers, use another background worker. This way the server can still go on processing the data. Eventually, you'll run out of background workers and you need to investigate what is causing the crash, but again, it's another way to keep you server up and running in such away that you can still shut it down/restart it from within the same program.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Ouch, then I cannot use them
I have to think about this; I could have a background worker for each "group" of clients and so a single "place" where the (group) data is processed, in its thread.
You'll be surprised how much information you can process with one background worker (especially when combined with async functions of B4J). With a pool of them, you can divvy out the work as needed (can use on worker as a dispatcher).
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
You'll be surprised how much information you can process with one background worker (especially when combined with async functions of B4J). With a pool of them, you can divvy out the work as needed (can use on worker as a dispatcher).
Ok, but I need to create dynamically many groups of clients - think to many chat-rooms that are continually being created and destroyed, I can't have a fixed number (and so a fixed number of background workers).
 
Upvote 0
Top