jorgen
RTC Expired
Posts: 20
|
|
« on: March 18, 2016, 02:19:47 PM » |
|
We currently use TRtcDataProvider to get data fra a database
I want to make this non blocking, calling the query in a thread.
The thread works, but it does not return any data
onDataReceived on the TRtcDataProvider
procedure TContendo_Actions.fn_DATASET(Sender: TRtcConnection); begin GetDataset(TRtcDataServer(Sender), Params); end;
in GetDataset I create a thread:
procedure TDBThread.WriteProcessedData; begin DataServer.WriteProcessedData (AString, true); end;
procedure TDBThread.Execute; begin Query.Open; sleep(10000); AString := TServer_Utils.JSONFromDataset(ViewDataset.Query); Synchronize(WriteProcessedData); end;
What is the best approach implementing this?
I read something about PrepareDelayedCall but that uses TRtcFunction and I use TRtcDataProvider
regards Jørgen
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #1 on: March 18, 2016, 03:25:01 PM » |
|
Why would you want to create a new thread manually for processing your data, then wait for that thread to finish in the Main Thread, if simply setting the "MultiThreaded" property on the TRtcHttpServer component to TRUE will make all your code running from a background thread?
Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
jorgen
RTC Expired
Posts: 20
|
|
« Reply #2 on: March 18, 2016, 05:41:49 PM » |
|
I have now set MultiThreaded = true
It seems to work, I use a connection pool for Firedac queries.
Should the server now be multi threaded?
Anything else I must do to support simultaneously users?
Jørgen
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #3 on: March 20, 2016, 11:06:11 AM » |
|
By setting the MultiThreaded property on the TRtcHttpServer component to TRUE, your Server will be Multi-Threaded, using the RTC thread pool. All events triggered by the TRtcHttpServer component, as well as any other RTC components linked to that component, will be executed from background threads (fully multi-threaded).
In a nutshell, when your Server is running in Multi-Threaded mode, RTC will be using a pool of Threads to execute all RTC code as well as all your code written inside RTC events from background threads. The number of threads in use will depend on the number of active Client connections and RTC Thread Pool parameters - defined through global variables in the rtcThrPool unit.
When using RTC components in Multi-Threaded mode, it is your responsibility to make sure that your code (everything inside RTC events) is thread-safe. Basically, the same rules apply here as when creating Threads manually and writing code to be executed inside background threads, with the only difference that you can use the "Sender.inMainThread" method to check if the event is being executed from the Main Thread and using the "Sender.Sync" method to call any RTC event (synchronized) from the Main Thread.
Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
jorgen
RTC Expired
Posts: 20
|
|
« Reply #4 on: March 22, 2016, 10:46:18 AM » |
|
Hello
If I do this on all events:
procedure TContendo_Actions.fn_DATASET(Sender: TRtcConnection); begin
if not Sender.inMainThread then begin Sender.Sync(fn_DATASET); end else begin //DO EVERYTHING end; end;
will everything be executed in main thread?
It would have been nice if so. Then I can take the event on by one to check if everything is thread save and focus on the most critical parts.
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #5 on: March 22, 2016, 12:20:22 PM » |
|
Yes, this construct will make sure that "// DO EVERYTHING" is execute from the Main Thread.
But ... synchronizing your code with the Main Thread in a Multi-Threaded Application is ONLY required when your code has to access the GUI (Graphical User Interface, like visual components on a Form). If your code does NOT require access to any GUI elements (for example, when accessing a Database through DataSets which are NOT linked to any visual controls on any Form), you can either use a sepatate set of components for each thread (for example, by writing a Datbase Connection Pool), or use a critical section (check "TCriticalSection" class in the "SysUtils" unit) to secure code sections which should NOT be executed from more than one thread at a time.
Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
jorgen
RTC Expired
Posts: 20
|
|
« Reply #6 on: March 22, 2016, 12:27:49 PM » |
|
Thanks
Only reason to do this was to be able to take one part first to make sure that it works.
I do everything you have suggested, but I have to make sure that everything works and that is easier if to check if I can take one event first.
Jørgen
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #7 on: March 22, 2016, 12:36:55 PM » |
|
Ok. Should you have any other questions, feel free to ask.
Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
jorgen
RTC Expired
Posts: 20
|
|
« Reply #8 on: March 29, 2016, 10:52:14 PM » |
|
Close, but one more problem
I can not get the sessions to work with MultiThreaded=true It does not always find the session.
do something like this:
procedure TContendo_Actions.fn_DATASET(Sender: TRtcConnection); begin
with TRtcDataServer(Sender) do begin Params := Request.Query['params'];
if FindSession(JSession.Value) then Result := TRUE;
Session.AsInteger['elementid']
end;
Creeate the session like this in another request, currently in the mainthread and is allways finnished befor the other request is used. with TRtcDataServer(Sender) do OpenSession;
Do I do something wrong?
The request fn_DATASET is executed async on client so session object must be thread safe.
Jørgen
|
|
|
Logged
|
|
|
|
jorgen
RTC Expired
Posts: 20
|
|
« Reply #9 on: March 30, 2016, 08:35:47 AM » |
|
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #10 on: March 30, 2016, 10:03:00 AM » |
|
In a nuthell ... If a Session exists, the FindSession method will return TRUE and LOCK that Session for exclusive use by the connection component calling the FindSession method. Any other calls to FindSession will return FALSE, for as long as the Session remains locked. The Session will be unlocked automatically when a request/response cycle of the connection component locking the Session has finished, but you can also unlock the Session manually by using the UnLockSession method. This "exclusive access" mechanism for Sessions is required to ensure that a Session can ONLY be used from one thread at a time. Using the same Session from multiple connections is NOT recommended, since there is always a chance that more than one connection will try to obtain access to the same Session. Check the other Topic for a more detailed explanation. Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
jorgen
RTC Expired
Posts: 20
|
|
« Reply #11 on: March 30, 2016, 12:52:26 PM » |
|
Hello Thanks
Now it works (probably)
calling UnLockSession was very important, if not, the session could be locked for a long time
Jørgen
|
|
|
Logged
|
|
|
|
|