I'm studying undertow because I've seen is a good choice if you want to implement Non-Blocking IO and you want to have a reactive http listener.
Undertow uses handlers to handle http requests in a Non-Blocking way.
If I have some logic to be implemented between request and response, how to make this logic to be Non-Blocking too, inside of an undertow handler?
I mean, if it's inserted (or called) within the handleRequest() method is already dispatched to a working thread and then already Non-Blocking or do you need to use CompletableFuture, or Rx Observable or any other reactive library, in order to guarantee that all the stack is reactive?
This is my Handler class as a title of example, I simulate to read a Json which will be parsed into a Person.class object and the transformed (business logic) and then returned back as a Json response.
I've written the two alternatives, in order to understand better how to make the whole stack reactive and Non-Blocking.
Which one do I have to use?
public class DoBusinessLogicHandler implements HttpHandler {
JsonConverter json = JsonConverter.getInstance();
#Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
Pooled<ByteBuffer> pooledByteBuffer = exchange.getConnection().getBufferPool().allocate();
ByteBuffer byteBuffer = pooledByteBuffer.getResource();
byteBuffer.clear();
exchange.getRequestChannel().read(byteBuffer);
int pos = byteBuffer.position();
byteBuffer.rewind();
byte[] bytes = new byte[pos];
byteBuffer.get(bytes);
byteBuffer.clear();
pooledByteBuffer.free();
String requestBody = new String(bytes, Charset.forName("UTF-8") );
/* FIRST ALTERNATIVE:
you can call the business logic directly because the whole body of handleRequest() is managed reactively
*/
Person person = (Person) json.getObjectFromJson(requestBody, Person.class);
Person p = transform(person);
sendResponse(exchange, json.getJsonOf(p));
/* SECOND ALTERNATIVE
you must wrap business logic within a reactive construction (RxJava, CompletableFuture, ecc.) in order to
have all the stack reactive
*/
CompletableFuture
.supplyAsync(()-> (Person) json.getObjectFromJson(requestBody, Person.class))
.thenApply(p -> transform(p))
.thenAccept(p -> sendResponse(exchange, json.getJsonOf(p)));
}
/* it could be also a database fetch or whatever */
private Person transform(Person p){
if(p!=null){
p.setTitle(p.getTitle().toUpperCase());
p.setName(p.getName().toUpperCase());
p.setSurname(p.getSurname().toUpperCase());
}
return p;
}
private void sendResponse(HttpServerExchange exchange, String response){
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "application/json");
exchange.getResponseSender()
.send(response);
}
}
Related
I am running into a bit of a chicken and an egg problem.
Case: A file is generated on a remote client. The client should transmit the file to the server over an asynccstub. The client must also transmit metadata via a blocking stub to be stored in a database.
Problems:
If I do the asynchronous operation first, then the file data is sent prior to the metadata, and therefore the server has no context as to what to name the file is, or where to put it. I originally intended to return this information from the server (bidirectionally), however stream observers do not lend themselves to set variables outside their anonymous definition.
If I do the synchronous operation first, I can get file naming information back from the server;however, I will need to package this into the "Chunks" of data. This would also require constantly opening and closing of the save file while GRPC iterates over it's stream data, as iterators are not easily reset (so i cant just peel off the first request).
As a last option, I could package all of this to the asynchronous request and dispatch with any synchronous call. I believe this will provide a working solution, but am concerned about the amount of data being sent on already large requests as well as the inefficiency mentioned before.
So my question is:
Is there a way to set a global variable to 'value.Message' from the response observer.
Alternatively, is there a way to pass information from the syncronous call to the asynchronous call on the server side?
Async response observer:
StreamObserver<GrpcServerComm.UploadStatus> responseObserver = new StreamObserver<GrpcServerComm.UploadStatus>() {
#Override
public void onNext(GrpcServerComm.UploadStatus value) {
if (value.getCode() != 1) {
Log.d("Error", "Upload Procedure Failure");
finishLatch.countDown();
}
}
#Override
public void onError(Throwable t) {
Log.d("Error", "Upload Response");
finishLatch.countDown();
}
#Override
public void onCompleted() {
finishLatch.countDown();
}
};
Relevant protobufs
message UploadStatus {
string filename=1;
int32 code = 2;
}
message DataChunk
{
string filename=1;
bytes chunk = 2;
}
message VideoMetadata
{
string publisher =1;
string description =2;
string tags = 3;
double videolat= 4;
double videolong=5;
}
service DataUpload
{
rpc UploadData (stream DataChunk) returns(UploadStatus);
}
service ContentMetaData
{
rpc UploadMetaData(VideoMetadata) returns (UploadStatus);
}
Python Server-side functions
class DataUploadServicer(proto_test_pb2_grpc.DataUploadServicer):
def UploadData(self,request_it,context):
response = proto_test_pb2.UploadStatus()
filename = str(random.getrandbits(32)) #server decides filename
response = filestream.writefile(filename,request_it)
return response
def writefile(filename, chunks):
response = proto_test_pb2.UploadStatus()
filename='tmp/'+filename
app_file = open(filename,"ab")
for chunk in chunks:
app_file.write(chunk.chunk)
app_file.close()
print('File Written')
response.Code=1
response.Message = "Succsesful write"
return response
Java users, a detailed article on this here.
I think it is not good idea to have these as 2 separate requests. Instead Metadata and DataChunk should be combined as 1 single type as shown here.
message FileUploadRequest {
VideoMetadata metaData = 1;
DataChunk dataChunk = 2;
}
Now you might ask why we have to send the metadata for every request! This is where gRPC oneof type helps.
message FileUploadRequest {
oneof upload_data {
VideoMetadata metaData = 1;
DataChunk dataChunk = 2;
}
}
Your service would be like this.
service FileuploadService {
rpc UploadData (stream FileUploadRequest) returns(UploadStatus);
}
When you use Oneof, In your generated code, oneof fields have the same getters and setters as regular fields. You also get a special method for checking which value (if any) in the oneof is set. First you send the metatdata and then you send the chunk. Based on, which oneof is set, then you can take the decision accordingly.
In a test, I'd like to look inside the body of a HttpRequest. I'd like to get the body as a string. It seems that the only way to do that, is to subscribe to the BodyPublisher but how does that work?
This is an interesting question. Where do you get your HttpRequest from? The easiest way would be to obtain the body directly from the code that creates the HttpRequest. If that's not possible then the next thing would be to clone that request and wraps its body publisher in your own implementation of BodyPublisher before sending the request through the HttpClient. It should be relatively easy (if tedious) to write a subclass of HttpRequest that wraps an other instance of HttpRequest and delegates every calls to the wrapped instance, but overrides HttpRequest::bodyPublisher to do something like:
return request.bodyPublisher().map(this::wrapBodyPublisher);
Otherwise, you might also try to subscribe to the request body publisher and obtain the body bytes from it - but be aware that not all implementations of BodyPublisher may support multiple subscribers (whether concurrent or sequential).
To illustrate my suggestion above: something like below may work, depending on the concrete implementation of the body publisher, and provided that you can guard against concurrent subscriptions to the body publisher. That is - in a controlled test environment where you know all the parties, then it might be workable. Don't use anything this in production:
public class HttpRequestBody {
// adapt Flow.Subscriber<List<ByteBuffer>> to Flow.Subscriber<ByteBuffer>
static final class StringSubscriber implements Flow.Subscriber<ByteBuffer> {
final BodySubscriber<String> wrapped;
StringSubscriber(BodySubscriber<String> wrapped) {
this.wrapped = wrapped;
}
#Override
public void onSubscribe(Flow.Subscription subscription) {
wrapped.onSubscribe(subscription);
}
#Override
public void onNext(ByteBuffer item) { wrapped.onNext(List.of(item)); }
#Override
public void onError(Throwable throwable) { wrapped.onError(throwable); }
#Override
public void onComplete() { wrapped.onComplete(); }
}
public static void main(String[] args) throws Exception {
var request = HttpRequest.newBuilder(new URI("http://example.com/blah"))
.POST(BodyPublishers.ofString("Lorem ipsum dolor sit amet"))
.build();
// you must be very sure that nobody else is concurrently
// subscribed to the body publisher when executing this code,
// otherwise one of the subscribers is likely to fail.
String reqbody = request.bodyPublisher().map(p -> {
var bodySubscriber = BodySubscribers.ofString(StandardCharsets.UTF_8);
var flowSubscriber = new StringSubscriber(bodySubscriber);
p.subscribe(flowSubscriber);
return bodySubscriber.getBody().toCompletableFuture().join();
}).get();
System.out.println(reqbody);
}
}
I have a library which is being used by customer and they are passing DataRequest object which has userid, timeout and some other fields in it. Now I use this DataRequest object to make a URL and then I make an HTTP call using RestTemplate and my service returns back a JSON response which I use it to make a DataResponse object and return this DataResponse object back to them.
Below is my DataClient class used by customer by passing DataRequest object to it. I am using timeout value passed by customer in DataRequest to timeout the request if it is taking too much time in getSyncData method.
public class DataClient implements Client {
private final RestTemplate restTemplate = new RestTemplate();
private final ExecutorService service = Executors.newFixedThreadPool(10);
// this constructor will be called only once through my factory
// so initializing here
public DataClient() {
try {
restTemplate.setRequestFactory(clientHttpRequestFactory());
} catch (Exception ex) {
// log exception
}
}
#Override
public DataResponse getSyncData(DataRequest key) {
DataResponse response = null;
Future<DataResponse> responseFuture = null;
try {
responseFuture = getAsyncData(key);
response = responseFuture.get(key.getTimeout(), key.getTimeoutUnit());
} catch (TimeoutException ex) {
response = new DataResponse(DataErrorEnum.CLIENT_TIMEOUT, DataStatusEnum.ERROR);
responseFuture.cancel(true);
// logging exception here
}
return response;
}
#Override
public Future<DataResponse> getAsyncData(DataRequest key) {
DataFetcherTask task = new DataFetcherTask(key, restTemplate);
Future<DataResponse> future = service.submit(task);
return future;
}
// how to set socket timeout value by using `key.getSocketTimeout()` instead of using hard coded 400
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
RequestConfig requestConfig =
RequestConfig.custom().setConnectionRequestTimeout(400).setConnectTimeout(400)
.setSocketTimeout(400).setStaleConnectionCheckEnabled(false).build();
SocketConfig socketConfig =
SocketConfig.custom().setSoKeepAlive(true).setTcpNoDelay(true).build();
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(300);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(200);
CloseableHttpClient httpClientBuilder =
HttpClientBuilder.create().setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig).setDefaultSocketConfig(socketConfig).build();
requestFactory.setHttpClient(httpClientBuilder);
return requestFactory;
}
}
DataFetcherTask class:
public class DataFetcherTask implements Callable<DataResponse> {
private final DataRequest key;
private final RestTemplate restTemplate;
public DataFetcherTask(DataRequest key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
#Override
public DataResponse call() throws Exception {
// In a nutshell below is what I am doing here.
// 1. Make an url using DataRequest key.
// 2. And then execute the url RestTemplate.
// 3. Make a DataResponse object and return it.
}
}
Customer within our company will use my library like this as shown below by using my factory in their code base -
// if they are calling `getSyncData()` method
DataResponse response = DataClientFactory.getInstance().getSyncData(key);
// and if they want to call `getAsyncData()` method
Future<DataResponse> response = DataClientFactory.getInstance().getAsyncData(key);
I am implementing sync call as async + waiting since I want to throttle them with the number of threads otherwise they can bombard our service without any control.
Problem Statement:-
I am going to add another timeout variable called socket timeout in my DataRequest class and I want to use that variable value (key.getSocketTimeout()) in my clientHttpRequestFactory() method instead of using hard coded 400 value. What is the best and efficient way to do that?
Right now I am using Inversion of Control and passing RestTemplate in a constructor to share the RestTemplate between all my Task objects. I am confuse now how to use key.getSocketTimeout() value in my clientHttpRequestFactory() method. I think this is mostly design question of how to use RestTemplate efficiently here so that I can use key.getSocketTimeout() value in my clientHttpRequestFactory() method.
I have simplified the code so that idea gets clear what I am trying to do and I am on Java 7. Using ThreadLocal is the only option I have here or there is any better and optimized way?
As Peter explains, using ThreadLocal is not a good idea here.
But I also could not find a way to "pass the value up the chain of method calls".
If you use plain "Apache HttpClient", you can create an HttpGet/Put/etc. and simply call
httpRequest.setConfig(myRequestConfig). In other words: set a request configuration per request
(if nothing is set in the request, the request configuration from the HttpClient which executes the request is used).
In contrast, the RestTemplate
calls createRequest(URI, HttpMethod) (defined in HttpAccessor)
which uses the ClientHttpRequestFactory. In other words: there is no option to set a request configuration per request.
I'm not sure why Spring left this option out, it seems a reasonable functional requirement (or maybe I'm still missing something).
Some notes about the "they can bombard our service without any control":
This is one of the reasons to use the PoolingHttpClientConnectionManager:
by setting the appropriate maximum values, there can never be more than the specified maximum connections in use (and thus requests running) at the same time. The assumption here is that you re-use the same RestTemplate instance (and thus connection manager) for each request.
To catch a flood earlier, specify a maximum amount of waiting tasks in the threadpool and set a proper error-handler
(use the workQueue and handler in this constructor).
ThreadLocal is a way to pass dynamic value which normally you would pass via method properties, but you are using an API you can't/don't want to change.
You set the ThreadLocal (possible a data structure containing multiple values) at some level in the thread stack and you can use it further up the stack.
Is this the best approach? NO, you should really pass the value up the chain of method calls, but sometimes this is not practical.
Can you provide an example of how my code will look like with ThreadLocal
You might start with
static final ThreadLocal<Long> SOCKET_TIMEOUT = new ThreadLocal<>();
To set it you can do
SOCKET_TIMEOUT .set(key.getSocketTimeout());
and to get the value you can do
long socketTimeout = SOCKET_TIMEOUT.get();
In my application I need to receive a byte array on a socket, parse it as a HttpRequest to perform some check and, if the checks passes, get back to the byte array and do some more work.
The application is based on NETTY (this is a requirement).
My first idea was to create a pipeline like this:
HttpRequestDecoder (decode from ByteBuf to HttpRequest)
MyHttpRequestHandler (do my own checks on the HttpRequest)
HttpRequestEncoder (encode the HttpRequest to a ByteBuf)
MyButeBufHandler (do my works with the ByteBuf)
However the HttpRequestEncoder extends the ChannelOutboundHandlerAdapter so it doesn't get called for the inbound data.
How can I accomplish this task?
It would be nice to avoid decoding and re-encoding the request.
Regards,
Massimiliano
Use an EmbeddedChannel in MyHttpRequestHandler.
EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestEncoder());
ch.writeOutbound(msg);
ByteBuf encoded = ch.readOutbound();
You'll have to keep the EmbeddedChannel as a member variable of MyHttpRequestEncoder because HttpRequestEncoder is stateful. Also, please close the EmbeddedChannel when you finished using it (probably in your channelInactive() method.)
I just had to encode and decode some HttpObjects and struggled a bit with it.
The hint that the decoder/encoder are stateful is very valuable.
That's why I thought I'll add my findings here. Maybe it's helpful to someone else.
I declared an RequestEncoder and a ResponseDecoder as a class member, but it still didn't work correctly. Until I remembered that the specific handler I was using the en/decoders within was shared...
That's how I got it to work in the end. My sequenceNr is to distinct between the different requests. I create one encoder and one decoder per request and save them in a HashMap. With my sequenceNr, I'm able to always get the same decoder/encoder for the same request. Don't forget to close and remove the de/encoder channels from the Map after processing the LastContent object.
#ChannelHandler.Sharable
public class HttpTunnelingServerHandler extends ChannelDuplexHandler {
private final Map<Integer, EmbeddedChannel> decoders = Collections.synchronizedMap(new HashMap<Integer, EmbeddedChannel>());
private final Map<Integer, EmbeddedChannel> encoders = Collections.synchronizedMap(new HashMap<Integer, EmbeddedChannel>());
.
.
//Encoding
if (!encoders.containsKey(currentResponse.getSequenceNr())) {
encoders.put(currentResponse.getSequenceNr(), new EmbeddedChannel(new HttpResponseEncoder()));
}
EmbeddedChannel encoderChannel = encoders.get(currentResponse.getSequenceNr());
encoderChannel.writeOutbound(recievedHttpObject);
ByteBuf encoded = (ByteBuf) encoderChannel.readOutbound();
.
.
//Decoding
if (!decoders.containsKey(sequenceNr)) {
decoders.put(sequenceNr, new EmbeddedChannel(new HttpRequestDecoder()));
}
EmbeddedChannel decoderChannel = decoders.get(sequenceNr);
decoderChannel.writeInbound(bb);
HttpObject httpObject = (HttpObject) decoderChannel.readInbound();
}
How about the put the EmbeddedChannel as the handler channel's attribute, instead of HashMap. Isn't it the same what you claim to solve the stateful encoder/decoder?
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.channel().attr(EMBEDED_CH).set( new EmbeddedChannel(new HttpRequestDecoder()));
super.channelActive(ctx);
}
#Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
EmbeddedChannel embedCh = ctx.channel().attr(EMBEDED_CH).get();
if (embedCh != null) {
embedCh.close();
}
super.channelInactive(ctx);
}
I need to create a server application with Netty that will receive requests both like "GETs" or "POSTs". In case of GET requests, the parameters would come as query parameters.
I have been checking that HttpRequestDecoder would be suitable for the GET requests, and HttpPostRequestDecoder for the post. But how could I handle both at the same time?
Not very familiar with Netty, so I would appretiate a little bit of help :)
The netty provisions us to handle a request as a pipeline where you define the pipeline as a sequence of handlers.
One sequence could be like this:
p.addLast ("codec", new HttpServerCodec ());
p.addLast ("handler", new YourHandler());
where p is an instance of ChannelPipeline interface. You can define the YourHandler class as follows:
public class YourHandler extends ChannelInboundHandlerAdapter
{
#Override
public void channelRead (ChannelHandlerContext channelHandlerCtxt, Object msg)
throws Exception
{
// Handle requests as switch cases. GET, POST,...
// This post helps you to understanding switch case usage on strings:
// http://stackoverflow.com/questions/338206/switch-statement-with-strings-in-java
if (msg instanceof FullHttpRequest)
{
FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
switch (fullHttpRequest.getMethod ().toString ())
{
case "GET":
case "POST":
...
}
}
}
}
You want to first check the request type and switch on the value (GET/POST/PUT/DELETE etc...)
http://docs.jboss.org/netty/3.1/api/org/jboss/netty/handler/codec/http/HttpMethod.html