OKHttp / retrofit: thread-safety / immutability of Call data - thread-safety

Can I pass the requestBody() headers() or anything else I retrieve from a finished OkHttp Call<> around to other threads, or is it necessary to copy the relevant data first?

You can pass the RequestBody to another thread, but only one thread is allowed to read the body. If multiple threads attempt to read it, you’re going to have a bad time.
Request and response headers are immutable.

Related

How to manage a slow callback function in the ESPAsyncWebServer library

I understand that delaying or yielding in the ESPAsyncWebServer library callbacks are a no-no. However, my callback function needs to query another device via the Serial port. This process is slow and will crash the ESP32 as a result.
Here is an example:
void getDeviceConfig(AsyncWebServerRequest *request) {
AsyncResponseStream *response =
request->beginResponseStream("application/json");
StaticJsonDocument<1024> doc;
JsonArray array = doc.createNestedArray("get");
for (size_t i = 0; i < request->params(); i++)
array.add(request->getParam(i)->value());
serializeJson(doc, Serial);
/* At this point, the remote device determines what is being asked for
and builds a response. This can take fair bit of time depending on
what is being asked (>1sec) */
response->print(Serial.readStringUntil('\n'));
request->send(response);
}
I looked into building a response callback. However, I would need to know ahead of time how much data the remote device will generate. There's no way for me to know this.
I also looked into using a chunked response. In this case, the library will continuously call my callback function until I return 0 (which indicates that there is no more data). This is a good start - but doesn't quite fit. I can't inform of the caller that there is definitely more data coming, I just haven't received a single byte yet. All I can do here is return 0 which will stop the caller.
Is there an alternative approach I could use here?
The easiest way to do this without major changes to your code is to separate the request and the response and poll periodically for the results.
Your initial request as you have it written would initiate the work. The callback handler would set global boolean variable indicating there was work to be done, and if there were any parameters for the work, would save them in globals. Then it would return and the client would see the HTTP request complete but wouldn't have an answer.
In loop() you'd look for the boolean that there was work to be done, do the work, store any results in global variables, set a different global boolean indicating that the work was done, and set the original boolean that indicated work needed to be done to false.
You'd write a second HTTP request that checked to see if the work was complete, and issue that request periodically until you got an answer. The callback handler for the second request would check the "work was done" boolean and return either the results or an indication that the results weren't available yet.
Doing it this way would likely be considered hostile on a shared server or public API, but you have 100% of the ESP32 at your disposal so while it's wasteful it doesn't matter that it's wasteful.
It would also have problems if you ever issued a new request to do work before the first one was complete. If that is a possibility you'd need to move to a queueing system where each request created a queue entry for work, returned an ID for the request, and then the polling request to ask if work was complete would send the ID. That's much more complicated and a lot more work.
An alternate solution would be to use websockets. ESPAsyncWebServer supports async websockets. A websocket connection stays open indefinitely.
The server could listen for a websocket connection and then instead of performing a new HTTP request for each query, the client would send an indication over the websocket that it wanted to the server to do the work. The websocket callback would work much the same way as the regular HTTP server callback I wrote about above. But when the work was complete, the code doing it would just write the result back to the client over the websocket.
Like the polling approach this would get a lot more complicated if you could ever have two or more overlapping requests.

Complete http.Request asynchronously in Golang

I want to put all arriving http.Requests into a queue and have a separate thread (goroutine?) process these requests and return the appropriate status.
However, the main http request handler directly completes the request even when the http.Request object is sent asynchronously to a goroutine.
Is there a way to control when the http.Request is completed and thereby asynchronously process it?
[Update]
I want to implement a producer-consumer model. The main request handler produces the requests and put them into a queue. A consumer thread (or threads) will read these requests, consume the body of the requests and return them.
http handlers are executed in a different goroutine per request, so if you are simply trying to free up the main serve loop, it's not neccesary.
If you are looking to serialize processing of requests, you could use a sync.Mutex and have your handler's lock on that. This would have a similar effect in that the requests would be handled one at a time.
I don't think sync.Mutex is fair, so it may not meet your needs.
also, if you wanted to be stateful between requests, then this is probably not the right solution.
As Jorge Marey mentioned, channels would work as well.
Though, i'd suggest you look at golang.org/x/net/context as it is a package specifically designed for multi-stage processing with timeouts and whatnot.
my guess is you will end up with a channel that passes structs that look like:
type Req struct{
ctx context.Context
w http.ResponseWriter
r *http.Request
}

Maintaining state in distributed application

I am creating an asynchronous application using zeromq, celluloid. I need to maintain the states for different tasks that depend on some response. I can do it by sending data about the state in the response params. But is there any better way to do this?
Use uniquely identified Conditions to wait for replies.
The question is very abstract/vague, so I will do the best I can to give you a functional example. If I understand/guess correctly, this is what you need to do:
Generate a UUID with Celluloid::Internals::UUID.generate before the request is made.
Package the request data, and send the UUID with the data.
Create a Condition, associated with that UUID.
Send the request.
Process the request, keeping the UUID associated with it.
Return the response, sending the UUID back with the reply data.
Process the response on a generic ( non-stated ) level... then signal the Condition with the data returned, locating the Condition in a thread-safe Hash by UUID.
Receive the data you needed within the stated object, by blocking at wait in that stated object... rather than processing the response directly.
The stated object ought to have no awareness of 0MQ which is by design stateless... it ought to communicate with a layer which makes requests, receives responses, and delivers the response to the object who asked for it, without that stated object losing its state, and without the state information being passed in the request or the response.
This strategy is used heavily by ECell which is forthcoming. Hopefully you are already using the celluloid-zmq gem for evented 0MQ support already.

Understanding goroutines for web API

Just starting out with Go and hoping to create a simple Web API. I'm looking into using Gorilla mux (http://www.gorillatoolkit.org/pkg/mux) to handle web requests.
I'm not sure how to best use Go's concurrency options to handle the requests. Did I read somewhere that the main function is actually a goroutine or should I dispatch each request to a goroutine as they are received? Apologies if I'm "way off".
Assuming you're using the Go's http.ListenAndServe to serve your http requests, the documentation clearly states that each incoming connection is handled by a separate goroutine for you. http://golang.org/pkg/net/http/#Server.Serve
You would usually call ListenAndServe from your main function.
Gorilla mux is simply a package for more flexible routing of requests to your handlers than the http.DefaultServeMux. It doesn't actually handle the incoming connection or request just simply relays it to your handler.
I highly suggest you read a bit of the documentation, specifically this guide https://golang.org/doc/articles/wiki/#tmp_3 on writing web applications.
I'm providing an answer even though I voted to close for being too broad.
Anyway, none of that is really necessary. You're over thinking it. If you haven't read this it looks like a decent tutorial; http://thenewstack.io/make-a-restful-json-api-go/
You can really just set up routes like you would with most typical rest frameworks and let the webserver/framework worry about concurrency at the request handling level. You would only employ goroutines to generate the response of a request, say if you needed to aggregate data from 10 files that are all in a folder. Contrived example, but this is where you would spin off 1 goroutine per file, aggregate all the information by reading off a channel in a non-blocking select and then return the result. You can expect all points of entry to your code are called in an asynchronous, non-blocking fashion if that makes sense...

Reading OkHttp ResponseBody data asynchronously

I'm using OkHttp's Call#enqueue to issue a couple dozen HTTP requests in parallel. In my callback, I'm given an Response with a ResponseBody. Because I have several requests in flight, I'd like to read data from the ResponseBody's source() without blocking. Is there some way to do that?
For example, if suppose there are 324 bytes available in a given ResponseBody, is there some way to read those bytes and then wait asynchronously for more data to be available (potentially reading data from other ResponseBody objects for other in-flight requests in the interim)?
Nope! OkHttp doesn't yet offer anything that flexible. You might want to look at Parallel Universe, which has hooked up OkHttp to fibers.

Resources