Multiple REST Requests in parallel with FireMonkey - multithreading

I'm building an Firemonkey app in Rad Studio XE7 where on single button click, I will need to do multiple( around 7) web service calls using TRestRequest. Every web service will return json object which will then populate dataset.
I'm looking for a way to these calls concurrently and not have UI of the app to lock.
Which way do you recommend to do this? I saw that Embarcadero introduced new Task and Feature functionality for threading, but I'm still not sure if we can use that and how. Also, I saw that there is a function to execute TRestRequest asynchronously, using this function:
function TCustomRESTRequest.ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true; AFreeThread: boolean = true): TRESTExecutionThread;
but I can't find any documentation on how to use this method and what it does.
Any input will be greatly appreciated.

The ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true; AFreeThread: boolean = true) method is indeed the way to go. As the name implies, it is asynchronous; meaning your program remains responsive after firing the request, or even after firing several requests.
However, it is important that you fire these different requests from different object instances; if you fire an ExecuteAsync from a TRESTRequest instance that is already performing an ExecuteAsync, the new request will get in the way of the existing request. You must create a separate TRESTRequest instance for each parallel call.
Note that its first parameter is a procedure; you pass a procedure of your choice as that parameter. The only requirement is that the procedure has the right signature; in this case, that it is a procedure that has no parameters.
The ExecuteAsync method is defined in REST.Client. (I've got Delphi XE-10.1. Berlin so it has one extra parameter, ACompletionHandlerWithError - which is called on error. The principle remains the same though).
Let's have a look:
function TCustomRESTRequest.ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true;
AFreeThread: boolean = true; ACompletionHandlerWithError: TCompletionHandlerWithError = nil): TRESTExecutionThread;
begin
Result := TRESTExecutionThread.Create(Execute, self, ACompletionHandler, ASynchronized, AFreeThread, ACompletionHandlerWithError);
end;
What happens here is that a new thread is created in which the REST Request is executed. If the response comes in, it is handled by ACompletionHandler.
By default, ACompletionHandler runs on the new thread created by ExecuteAsync. If you want it to run on the main thread, you should set ASynchronized to true.
But how do you get access to that response, and make it accessible to the rest of your program?
FireMonkey's TRESTRequest class has a property Response, that refers to the TRESTResponse object that contains the server's response to our request.
Unfortunately, neither the TRESTRequest nor the TRESTResponse object are passed to our CompletionHandler!
So we need to somehow give the CompletionHandler this information. Fortunately, we can use a method as a CompletionHandler.
Let's assume that the class that is going to process the resulting data is called DataOwner. Our purpose is that DataOwner has access to the TRESTResponse instance associated with our TRESTRequest instance.
The easiest way to do this is to make TRESTRequest and/or TRESTResponse a member of DataOwner.
Assume your request was fired from a TRESTRequest instance named MyRESTRequest and processed by a function processResponse, you would use the following code:
type TDataOwner = class
MyData: TSomeDataType;
procedure GetData();
procedure FillDataSet();
end;
implementation
procedure DataOwner.GetData();
begin
// ... initialize MyRESTRequest here...
MyRESTRequest.ExecuteAsync(FillDataSet);
end;
procedure DataOwner.FillDataSet();
begin
MyData := processResponse(MyRESTRequest.Response);
end;
If you want to fire several requests in parallel, you need to use this pattern several times. It is unfortunate that we don't have direct access to the TRESTRequest instance or TRESTResponse instance in our Completion Handlers, because this means we have to do the bookkeeping ourselves. In other words, it is up to the programmer to make sure that the Completion Handler processes the right Response object.

Related

Response from service as a callback is not concurrent in actionscript?

I am developing an AIR application for iOS/ Android and I am using a backend service for database operations. The backend service provides asynchronous API's for loading and saving the data. I happen to stumble at a piece of logic which caught my attention:
Main
public funciton loadPlayerData():void
{
service.loadData();
// Busy lock
while( !service.client == true );
// Do some stuff after the client is received
}
Service
public function loadData()
{
// Call the external service and specify success callback as
// onSuccess
}
public function onSuccess():void
{
this.client = true;
}
public var client:Boolean = false;
What I am trying to do in the above code is that I am calling an async operation on service and while it is fetching data from server, I am busy spinning waiting for the client to set true in the callback. According to my understanding, this is how locking is done for resources in operating system and all. ( Though there are more elegant solutions in operating system other than busy wait ).
But the results are such that the Main gets stuck in an infinite busy waiting implying that onSuccess never gets called. The reason, according to my understanding is that until and unless the the current execution ends ( or when the stack of current execution is completely popped out), control is not given to the callback Function and hence my implementation results in never ending spin wheel. My basic assumption that thread is multiplexed from time point of view is flawed and thats the explanation I can deduce from the premise.
I want to know whats the actual reason behind the above scenario? How far I am correct in my deduction and what are the details behind execution of actionscript code in scenario like these ?
The AS3 runtime is not multithreaded - your script runs on a single thread with certain operations internally running on a separate thread (like network calls, etc.) The only way to properly handle your situation is to split up your work into multiple steps; you then initiate the first step (calling the remote service) and pass a callback function. There's no need to wait in a loop (in fact, it hurts you as you discovered) - when the network call is done, your callback will be called and you can initiate the next step of your processing. Until this 2nd step is called, the rest of your program should assume that the data from the remote service is not available.
Your code would be something like:
public funciton loadPlayerData():void
{
service.loadData();
// Nothing else here - you must wait for the data
// to be avaiable.
}
public function loadData()
{
// Call the external service and specify success callback as
// onSuccess
}
public function onSuccess():void
{
// Call logic that performs "Do some stuff
// after the client is received" from your
// question.
}
I think this should solve the issue, depending on how you determine that onSuccess is called (I assume its a function for an Event Listener.)
First off, your Service class needs to inherit EventDispatcher, either directly or indirectly, so that you gain access to dispatchEvent(event) function.
Main
public funciton loadPlayerData():void
{
service.loadData();
service.addEventListener(Event.COMPLETE, onServiceLoadedData);
}
private function onServiceLoadedData(e:Event):void{
...
}
Service
...
public function onSuccess():void
{
//after everything has been loaded
dispatchEvent(new Event(Event.COMPLETE));
}
As a side note, if you need to access stuff from your Service class and you don't want to handle it through setter/getter variables and such like, you can make a custom Event and pass all the necessary Information there.

SignalR Wait for result

Trying to push a message into UI and receive some result to return in synchronous way from web-service.
Method code goes as follows.
[OperationContract]
public string DecypherCaptcha(string captcha)
{
var connection = new HubConnection("http://localhost:51806");
IHubProxy hub = connection.CreateHubProxy("robo");
string decaptcha = null;
hub.On("captchaDecyphered", decyphered =>
{
decaptcha = decyphered;
});
connection.Start().Wait();
hub.Invoke<string>("DecypherCaptcha", new object[] { captcha });
return decaptcha;
}
The issue is that method finishes before value is obtained from hub's captchaDecyphered. However the expression { decaptcha = decyphered; } triggers fine from server after method exits.
Adding ManualResetEvent flag and WaitOne() for it doesn't solve the problem freezing the execution and preventing hub.On("captchaDecyphered" from firing.
Any ideas how to synchronize this?
UPDATE#1 Small notice. Cannot avoid using the intermediate synchronous WCF web-service acting as SignalR client, because of pretty specific robots sitting behind, which are able to interact with outer world only by calling webservices synchronously. Basically in this scenario when robot faces captcha it calls the web-service passing it via SignalR to UI for manual recognition.
UPDATE#2 Thanks to #Ken's inspiring advice got it working by enclosing the connection establishing and hub method invocation into separate 'Thread' followed by waiting with 'ManualResetEvent':
new Thread(() =>
{
connection.Start().Wait();
hub.Invoke<string>("DecypherCaptcha", new object[] { captcha });
}).Start();
sync.WaitOne();
Have previously been trying to start from 'Task' supposing it would run on separate thread implicitly, but with no luck.
You could have the DecypherCaptcha hub method on the SignalR server return the deciphered captcha as a Task<string> instead on invoking captchaDecyphered.
You may want to use a TaskCompletionSource to help you create the appropriate task. Basically you could call tcs.SetResult(deciphered) and return tcs.Task instead of calling Clients.Caller.captchaDecyphered(deciphered).
Then your client-side code code would simply be:
[OperationContract]
public string DecypherCaptcha(string captcha)
{
var connection = new HubConnection("http://localhost:51806");
IHubProxy hub = connection.CreateHubProxy("robo");
connection.Start().Wait();
return hub.Invoke<string>("DecypherCaptcha", captcha).Result;
}
You've got several options.
(1) Spin off the request to the SignalR hub onto a separate thread, probably using the static ThreadPool class, and then add in all the ManualResetEvent stuff. That way it won't block when you're waiting on the SignalR method to return.
(2) Make the DecypherCaptcha method asynchronous. It looks to me like the DecypherCaptcha() is intended to be a WCF method that in turn wraps a SignalR method. If that's the case, forgetting for a moment whether this is a wise approach, you could still call a WCF method on the client when the captchaDecyphered SignalR method completes. But if it's not intended to be a WCF method, then you could have DecypherCaptcha() either (a) return a Task<T>, and only flag the Task to be complete when the captchaDecyphered completes; or (b) pass in a Func<T> as a continuation parameter, and call that when the captchaDecyphered completes.
In general, one of the things that makes asynchronous programming difficult is that except for the very top-level method, you generally need to make every method that calls an asynchronous method itself asynchronous, all the way up and down the stack, either through the Async pattern (nasty), or continuation passing (better) or through a Task object + async/await (probably best). So adding in a single asynchronous method often results in significant changes to your application, all the way through. That's one of the many reasons why the new async and await keywords in .NET 4.5 are so helpful, because they help to encapsulate the necessary changes when you start making your application asynchronous.
You can use the generic Invoke method where you can specify the type of result you expect. With the method you CAN use .Result to wait for the result.
string result = IHubProxy.Invoke<string>("GetString").Result;

Delphi accessing OleObject from 2 different threads

I have some inherited code for opening IE and I have some troubles, here is what I have:
IEUnit.pas (no form) has routines for LoadIE and OpenIE
OpenIE is called from separate thread and it looks like this
procedure OpenIE(URL: OleVariant; FieldValues: string = '');
var ie : IWebBrowser2; // <-- This should become "global" variable for the IEUnit
begin
ie := CreateOleObject('InternetExplorer.Application') as IWebBrowser2;
ie.Navigate2(URL, Flags, TargetFrameName, PostData, Headers);
ShowWindow(ie.HWND, SW_SHOWMAXIMIZED);
ie.Visible := true;
...
end;
I would like to have "global" ie variable in the unit and to write LoadIE routine like this :
LoadIE should be called from FormCreate (main thread)
It should just create "global" ie object
ie := CreateOleObject('InternetExplorer.Application') as IWebBrowser2;
so the OpenIE function doesn't need to create it, just to use it (purpose is to speed things up)
So problem is how to access same OLE object from 2 different threads, one creates the object, the other one uses it.
When I write code that doesn't take care of threads I get an error
exception class EOleSysError with message 'The application called an interface that was marshalled for a different thread'
How should I do it, to take care of threads (I'm not experienced with threads, some reading and video links are welcome).
Thanks in advance
MTA model COM servers can only be used from within their associated apartment. Here's the explanation of the error with the following advice:
The correct way of transferring an interface pointer (either a direct
pointer or a proxy pointer) from one apartment to another is via COM's
marshaling mechanism. The source apartment can call
CoMarshalInterThreadInterfaceInStream() to marshal the interface
pointer to a shared (global) stream. The destination apartment can
unmarshal this interface pointer by calling
CoGetInterfaceAndReleaseStream().
As you know, because it was the subject of your previous question, you need all calls to the COM object to be made from the same thread. The obvious choice is the main GUI thread. So, create the IWebBrowser2 in your main form's OnCreate event handler. And then use TThread.Synchronize or TThread.Queue whenever you need to show the browser. The code that you pass to Synchronize or Queue will be executed on the main GUI thread.
Assuming you are using a modern version of Delphi with support for anonymous methods you'd write it like this:
procedure TMyThread.ShowBrowser(const URL: string);
var
Proc: TThreadProcedure;
begin
Proc := procedure
begin
MainForm.Browser.Navigate2(URL, ...);
ShowWindow(MainForm.Browser.HWND, SW_SHOWMAXIMIZED);
MainForm.Browser.Visible := true;
end;
Queue(Proc);
end;
Non-free-threaded COM objects can only be used by/on/in the same thread as the one it's created for/on/in/with. In your case, to speed things up, I would use a plain global treadvar value of type IWebBrowser2, or a property in your class overriding TThread.
use CriticalSection to wrap all calls to the OleObject. also use Synchronize to call from the "other" thread to the main UI thread (this is why you get the exception).

Silverlight - Waiting for asynchronous call to finish before returning from a method

I have a Silverlight application that uses WCF services and also uses the Wintellect Power Threading library to ensure logic executes fully before the application continues. This is achieved by calling back to the application using delegates so it can continue after the service call has completely finished.
I wish to achieve the same thing in another part of my application but without the use of callbacks e.g. call method that uses WCF service to say load an object from the database, wait for this to return and then return the Id of the object from the original method called.
The only way I could see to do this was to carry out the call to the WCF service in a helper library which loads the object on a different thread and the original method would keep checking the helper library (using static variables) to wait for it to complete and then return it.
Is this the best way to achieve this functionality? If so here are details of my implementation which is not working correctly.
public class MyHelper
{
private static Thread _thread;
private static User _loadedObject;
public static GetUser()
{
return _loadedObject;
}
public static void LoadObject(int userId)
{
_loadedObject = null;
ParameterizedThreadStart ts = new ParameterizedThreadStart(DoWork);
_thread = new Thread(ts);
_thread.Start(userId);
}
private static void DoWork(object parameter)
{
var ae = new AsyncEnumerator();
ae.BeginExecute(DoWorkWorker(ae, Convert.ToInt32(parameter)), ae.EndExecute);
}
private static IEnumerator<Int32> DoWorkWorker(AsyncEnumerator ae, int userId)
{
// Create a service using a helper method
var service = ServiceHelper.GetService<IUserServiceAsync>();
service.BeginGetUserById(userId, ae.End(), null);
yield return 1;
_loadedObject = service.EndGetUserById(ae.DequeueAsyncResult());
_thread.Abort();
}
}
My method then is:
public int GetUser(int userId)
{
MyHelper.LoadObject(userId);
User user = MyHelper.GetUser();
while (user == null)
{
Thread.Sleep(1000);
user = MyHelper.GetUser();
}
return user.Id;
}
The call to the get the user is executed on a different thread in the helper method but never returns. Perhaps this is due to the yield and the calling method sleeping. I have checked the call to get the user is on a different thread so I think everything should be kept separate,
The whole construct you are using does not match current best practices of Silverlight. In Silverlight your data access methods (via WebServices of course) are executed asynchronously. You should not design around that, but adapt your design accordingly.
However calling services sequentially (which is different than synchonously) can be valid in some scenarios. In this blog post I have shown how to achieve this by subscribing the Completed event of the remote call and block the UI in the meantime, with which the workflow looks and feels like normal async calls.
I believe calls to the server from Silverlight apps use events that fire on the UI thread; I think that's part of the Silverlight host environment in the browser and can't be worked around. So trying to call back to the server from another thread is never going to end well. If you are waiting in program code in the UI thread, your never going to get the call result events from your WCF calls.
You can simulate a synchronous call from a non-UI thread with a callback on the UI thread, but that is probably not what you want. It's better to bite the bullet and make your program logic work with the async calls Silverlight gives you.
If you code against the Interface created for your service reference you can call the Begin and End methods 'synchronously' for each one of your service calls, we then pass in an Action<T> to execute after the End methods has completed. Take note that you have to do this from a dispatcher. This is very close to making a synchronous call as the code to run after the call is still written where the call is made, and it executes after the service call is completed. It does however involve creating wrapper methods but we also worked around that by hiding our wrappers and generating them automatically. Seems like a lot of work but isn't, and ends up being more elegant than all the event handlers etc. Let me know if you need more info on this pattern

Is there any problem to using this code in a Thread ? (Delphi)

i use this code in a thread (through Indy Onexecute event) . is there any problem ?
function TFrmMain.ShellExecute_AndWait(FileName, Params: string): bool;
var
exInfo: TShellExecuteInfo;
Ph: DWORD;
begin
FillChar(exInfo, SizeOf(exInfo), 0);
with exInfo do
begin
cbSize := SizeOf(exInfo);
fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT;
Wnd := GetActiveWindow();
exInfo.lpVerb := 'open';
exInfo.lpParameters := PChar(Params);
lpFile := PChar(FileName);
nShow := SW_NORMAL;
end;
if ShellExecuteEx(#exInfo) then
Ph := exInfo.hProcess
else
begin
Result := true;
exit;
end;
while WaitForSingleObject(exInfo.hProcess, 50) <> WAIT_OBJECT_0 do
begin
end;
CloseHandle(Ph);
Result := true;
end;
MSDN has this advice:
Because ShellExecuteEx can delegate execution to Shell extensions (data sources, context menu handlers, verb implementations) that are activated using Component Object Model (COM), COM should be initialized before ShellExecuteEx is called. Some Shell extensions require the COM single-threaded apartment (STA) type. In that case, COM should be initialized as shown here:
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)
There are instances where ShellExecuteEx does not use one of these types of Shell extension and those instances would not require COM to be initialized at all. Nonetheless, it is good practice to always initalize COM before using this function.
(In Delphi, you'd of course replace the first parameter with nil and use or for the bitwise operation.)
Raymond Chen recently wrote about the consequences of getting this wrong. The specific example was that the function might fail with the Error_Access_Denied error code.
That's the only potential multithreading issue I see in your code. Below are further things that occurred to me when I read your code, although they have nothing to do with multithreading (and not even much to do with Indy).
You have a peculiar way of waiting for the program to stop running. You repeatedly wait for 50 milliseconds at a time, but if the process isn't finished yet, you do nothing but wait again. Describe your intention more accurately by specifying Infinite for the timeout.
The function always returns True. If there's no useful return value, then you should just make it a procedure so there's no return value at all. Don't confuse the caller with useless information. If you're going to keep it as a function, then use the Delphi native type Boolean instead of the Windows compatibility type Bool for the return type.
I'm a little wary about the idea of a server executing user-interactive programs upon receipt of network messages.
Notice when MSDN says you might not get a process handle. There are cases when ShellExecuteEx can service your request without creating a new process, so you'll have nothing to wait on.
The user might end up using the program awhile, and your server will be stuck waiting all that time. I wonder whether it really needs to wait at all. Is the client going to be waiting for a response from the server, too?

Resources