Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call to rest api breaks after first successful call #96

Open
sigfrid696 opened this issue Mar 21, 2020 · 7 comments
Open

Call to rest api breaks after first successful call #96

sigfrid696 opened this issue Mar 21, 2020 · 7 comments

Comments

@sigfrid696
Copy link

sigfrid696 commented Mar 21, 2020

Hello,

first of all thanks for your beautiful library.

I have the following problem, maybe I'm doing something wrong but I don't understand what...

This is my code, very simple and taken from one of the tutorials.

I create at startup the client in this way: I register my url and then create client.

url = _url;
client = restc_cpp::RestClient::Create();

Then I start calling a Rest API (which is tested from other not c++ clients and has no working problems) which returns a list of objects, Image objects in this case.
This is the method that I call several times in a loop with different "vid" parameter passed to the function:

std::list<OCRModels::Image> OCRAPIClient::GetImages(std::string vid)
{
	std::string completeUrl = url + "/" + REST_GETIMAGES + "/" + vid;
	std::list<OCRModels::Image> images;
	client->Process([&](restc_cpp::Context& ctx) {
		try {
			SerializeFromJson(images,
				restc_cpp::RequestBuilder(ctx)
				.Get(completeUrl)
				.Header("OCR-Client", "RESTC_CPP")
				.Execute());
		}
		catch (std::exception ex)
		{
			std::cerr << "Error calling " << completeUrl << " : " << ex.what() << std::endl;
		}	
	});
	client->CloseWhenReady(true);

	return images;
}

I understand that this is calling the lambda in a co-routine managed by boost library.

The first call always works good giving back the correct list of images.
Then if I try another call in the loop, the lambda is never called again...
If I destroy the client object before every call everything works good.

Did I miss something ? What's wrong in my code ?

Thank You, your work is much appreciated.

Best Regards

Alessandro

@jgaa
Copy link
Owner

jgaa commented Mar 29, 2020

Don't call CloseWhenReady() here. Call it in the main() function if you need to prevent it from exiting the application before the rest operations are done.

@sigfrid696
Copy link
Author

sigfrid696 commented Mar 30, 2020

Hello, I tried you solution, but if I move CloseWhenReady() in main function at the end, then the list is always empty after the call to GetImages method.

Then I tried in another way. I don't need the function to be asynchronous, because I need to wait the call to GetImages before doing other things and moving ahead in the code.
So I tried using the current thread instead of creating a new one.
I changed the code in this way (as in another your tutorial).

client = restc_cpp::RestClient::CreateUseOwnThread();

and

std::list<OCRModels::Image> OCRAPIClient::GetImages(std::string vid)
{
	std::string completeUrl = url + "/" + REST_GETIMAGES + "/" + vid;
	std::list<OCRModels::Image> images;
	client->Process([&](restc_cpp::Context& ctx) {
		try {
			SerializeFromJson(images,
				restc_cpp::RequestBuilder(ctx)
				.Get(completeUrl)
				.Header("OCR-Client", "RESTC_CPP")
				.Execute());
		}
		catch (std::exception ex)
		{
			std::cerr << "Error calling " << completeUrl << " : " << ex.what() << std::endl;
		}	

		client->CloseWhenReady(true);
	});
	//client->CloseWhenReady(true);

	// Start the io-service, using this thread.
	client->GetIoService().run();

	return images;
}

Is my understanding correct ? Is this using only the main current thread and not creating another thread ?
No luck also in this case. The first call always works good giving back the correct list of images. Then the next calls return an empty list...

@jgaa
Copy link
Owner

jgaa commented Mar 31, 2020

CloseWhenReady is used to tell the library to finish whatever it is doing and then quit. It can be used to hold the main thread off until the requests finish. But if you have more work, don't call it at all.

If you have more work, just make sure that the main thread don't exit the main() function, or use the main thread to handle the IO. Don't call CloseWhenReady() until you have finished all your requests.

@sigfrid696
Copy link
Author

sigfrid696 commented Mar 31, 2020

CloseWhenReady is used to tell the library to finish whatever it is doing and then quit. It can be used to hold the main thread off until the requests finish. But if you have more work, don't call it at all.

If you have more work, just make sure that the main thread don't exit the main() function, or use the main thread to handle the IO. Don't call CloseWhenReady() until you have finished all your requests.

Ok I understand.
I supposed that calling CloseWhenReady() function was the way to wait for the requests to be executed. If I remove it, the thread doesn't wait for each request to end, so each result is always empty. How am I supposed to wait for each request to end and then collect the results ? Is there any other function to call ? This is not clear to me.

I would like to go synchronous for my needs, is the last code I posted the right way ? It doesn't seem ok to me because I don't have a way to wait for the lambda to be executed if I remove CloseWhenReady call, so the list of images is always empty...
The solution could be to use ProcessWithPromise but it seems to work only with coroutine. How can I make
client->GetIoService().run();
terminate in a synchronous scenario without calling
client->CloseWhenReady(true);

Sorry for so many question but maybe now I'm near to the solution
Many thanks for your attention

@jgaa
Copy link
Owner

jgaa commented Mar 31, 2020

The point with asynchronous programming is not to wait. You get the result inside the lambda, and while the request is pending, your threads are free to do away with other work. If you /really/ want to wait on the outside, you can use a std::future for that.

@sigfrid696
Copy link
Author

sigfrid696 commented Apr 6, 2020

The point with asynchronous programming is not to wait. You get the result inside the lambda, and while the request is pending, your threads are free to do away with other work. If you /really/ want to wait on the outside, you can use a std::future for that.

Sometimes it is a good choice to do synchronous requests, depending on the overall architecture of the system...
Very last question, can I consider the calls to the methods Process and ProcessWithPromise thread safe (i.e. can the same RestClient object be called by different threads) or do I have to protect calls externally ?
Thanks

@KingDuckZ
Copy link

This is an interesting question actually: do I have to protect the RestClient object with a mutex when I call ProcessWithPromise()?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants