B4J Question [RESOLVED] HTTPS Web Server and Thread Management

Jmu5667

Well-Known Member
Licensed User
Longtime User
Hello

I have a HTTPS web server and a web socket class to handle each connection. I have a simple B4A app that connects to the server and receives 64 bytes every 10 seconds, so the connection to the server is always on. (BTW this is all early development code to figure out how things should be done)

So, yesterday evening I loaded up VisualVM so I could monitor the thread that is connected. This morning when I checked VisualVM this is what I saw:

upload_2018-1-24_9-32-2.png


The above show that over 5500 threads had been created by one connection. I am not sure if this is normal.

Here is the code for the WebSocket Class

B4X:
'WebSocket class
Sub Class_Globals
   
   Private ws As WebSocket
   Private timer1 As Timer
   Private session_id As String
   
End Sub

Public Sub Initialize
   
   DateTime.DateFormat = "yyyy-MM-dd"
   DateTime.TimeFormat = "HH:mm:ss.SSS"
   
   Log(DateTime.date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & ":" & session_id & ":INFO:websocket.Initialize")
   
End Sub

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
   
   Log(DateTime.date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & ":" & session_id & ":INFO:websocket.Connected")
   ws = WebSocket1
   Dim session As HttpSession = ws.UpgradeRequest.GetSession
   session_id = session.Id
   Log(DateTime.date(DateTime.Now) & " " & DateTime.Time(DateTime.Now)& ":" & session_id  & ":INFO:websocket.Socket " & ws.Secure)
   timer1.Initialize("timer1", 10000)
   timer1.Enabled = True
   
End Sub

Sub Timer1_Tick
   
   Dim s As String
   
   timer1.Enabled = False
   Dim APSU As ApacheSU
   ' // create 1MB
   s = APSU.Repeat("W",64) ' 128k
   ' // send
   ws.RunFunction("ServerTime", Array As Object(s))
   ws.Flush
   Log(DateTime.date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & ":" & session_id  & ":INFO:websocket.Timer1_Tick:SEND")
   timer1.Enabled = True
   
End Sub


Sub Device_Message(Params As Map)
   
   Log("Device message: " & Params.Get("message"))
   
End Sub


Private Sub WebSocket_Disconnected
   
   timer1.Enabled = False
   Log(DateTime.date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & session_id  & ":INFO:websocket.Disconnected")
   
End Sub

It would appear that a new thread(s) is created each time the send occurs. I would appreciate any comments on this.

Regards

John.
 

Jmu5667

Well-Known Member
Licensed User
Longtime User
Note that there are only 25 live threads.

What is ApacheSU?

A new thread is not created when you send data.

Are you monitoring the logs? Do you see many "INFO:websocket.Connected" messages?

ApacheSU is a library fo string utilites - https://www.b4x.com/android/forum/threads/90-string-manipulation-methods.73564/#content

Yes, I am monitoring the logs and for the single connection there is only 1 "INFO:websocket.Connected"

Yes is there is only 25 live threads, I was curious about the amount of threads that were created by a single connection and noticed the thread created each time I send some data.

regards john
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
These are probably threads that are created by jetty and are shared by all clients. The important number is the number of live threads. It is possible that over time it starts and stops many threads.

Ok, so nothing to worry about ?
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
FYI

I discovered what was creating all the the threads:

B4X:
Sub Timer1_Tick
   
   
   
   'timer1.Enabled = False
   
   ' // we are done   
   If killMe Then
       ws.Close
       Return
   End If
   
   If mCode.Length > 0 Then
       send_some_data
   End If
   
   'timer1.Enabled = True
   
End Sub

On entry I was turning off the timer, and turning it back on when exiting

J.
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
This is not needed. A timer will never tick until the current code finishes executing.
Ok, can I ask about the ConnectionPool management or should I open a new question, reason being when my socket connection closes, there are still threads active with this :

B4X:
2018-01-25 09:19:15

"pool-1-thread-3" - Thread t@43
   java.lang.Thread.State: WAITING
   at sun.misc.Unsafe.park(Native Method)
   - parking to wait for <166e10> (a java.util.concurrent.SynchronousQueue$TransferStack)
   at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
   at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
   at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
   at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)
   at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
   at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
   - None

J.
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Websocket Class:

B4X:
'WebSocket class
Sub Class_Globals
  
   Private sql               As SQL
   Private ws                As WebSocket
   Private session_id        As String
   Private mCode            As String
  
End Sub

Public Sub Initialize
  
   DateTime.DateFormat = "yyyy-MM-dd"
   DateTime.TimeFormat = "HH:mm:ss.SSS"
  
   writelog("Initialize")
  
End Sub

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
  
   ws = WebSocket1
  
   Dim session As HttpSession = ws.UpgradeRequest.GetSession
   session_id = session.Id
   writelog("WebSocket_Connected, is secure " & ws.Secure & ", session id = " & session_id)
  
End Sub

Sub getSqlConnection
  
  
   Try
       ' // get a connection to the system db
       sql = Main.DB_SQL.GetConnection
       writelog("getSqlConnection, IsInitialized = " & sql.IsInitialized)
   Catch
       writelog("getSqlConnection, error - " & LastException)
       close_socket
   End Try
  
  
End Sub

Sub closeSqlConnection
  
   Try
       ' // get a connection to the system db
       sql.Close
       writelog("closeSqlConnection, IsInitialized = " & sql.IsInitialized)
   Catch
       writelog("closeSqlConnection, error - " & LastException)
       close_socket
   End Try
  
  
End Sub

Sub close_socket
  
   closeSqlConnection
   ws.Close
  
End Sub

Sub send_some_data
  
   Dim s As String
   Dim rs As ResultSet

   ' // get a SQL connection
   getSqlConnection
   ' // do we have a connection
   If sql.IsInitialized Then
       ' // do a query
       rs = sql.ExecQuery("SELECT public_id, account_name from [IS_SYSTEM].dbo.c_users " & _
                           "WHERE public_id = '" & mCode & "' OR (" & _
                                   "phone_1 = '" & mCode & "' OR " & _
                                    "phone_2 = '" & mCode & "' OR " & _
                                    "phone_3 = '" & mCode & "' OR " & _
                                    "phone_4 = '" & mCode & "')")
                                  
       ' // go data
       If rs.nextrow Then
           ' // send
           ws.RunFunction("ServerTime", Array As Object(rs.GetString("account_name"),generate_session_id))
           ws.Flush
           writelog("send_some_data() Sending Data," & rs.GetString("account_name") & ", " & generate_session_id)
       Else
           s = "Invalid code " & mCode
           ws.RunFunction("ServerTime", Array As Object(s))
           ws.Flush
           writelog("send_some_data() Invalid Code " & mCode)
           mCode = ""
       End If
       rs.Close
   Else
       writelog("send_some_data() sql.IsInitialized = " & sql.IsInitialized)
   End If
  
   ' // close connectio to sql
   closeSqlConnection
  
End Sub

Sub generate_session_id As String
  
   Dim res As String
   Dim x As Int
   Dim bc As ByteConverter
   Dim b As Byte
  
  
   For x = 1 To 16      
       b = Rnd(33,255)
       res = res & bc.HexFromBytes(Array As Byte(b))
   Next
  
   Return res
  
End Sub

Sub Device_Message(Params As Map)
  
   mCode = Params.Get("message")
   send_some_data
  
End Sub


Private Sub WebSocket_Disconnected
  
   writelog("websocket.Disconnected")
  
End Sub


Sub writelog(pData As String)
  
   DateTime.DateFormat = "yyyy-MM-dd"
   DateTime.TimeFormat = "HH:mm:ss.SSS"
  
   Log(DateTime.date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & ":" &session_id  & ":INFO:WebSock:" & pData)
  
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Is this normal behavior for the connetionpool or do I have a "Thread leak"
I would say that this is normal. Allocating and deallocating resources (memory, threads, sockets, etc.) is computationally expensive. To lessen the computational expense, one may pre-allocate resources and hold on to them (your trading computation expense for resource expense). This can be true for the DB pooling and the WebSocket usage. Using such technologies often entails giving up some of the control that you have over your resources and having a larger resource usage when using such technologies (and at the same time reap the benefits of using these technologies). With the amount of resources we have available in computers today, that should not be an issue. Please note that the DB pooling is based on c3p0 (http://www.mchange.com/projects/c3p0/) and the WebSocket interface is based on Jetty's WebSockte API (http://www.eclipse.org/jetty/documentation/9.4.x/jetty-websocket-server-api.html). Both these technologies are mature and I would first blame my own code for any "leakage".
 
Upvote 0
Top