I have a question regarding configuration of timeouts on a netty TCP server. Right now, I set the connect timout like this:
serverBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 20000);
This seems to work, all good and well. Now I wonder if it's possible to define a "read timeout" on the server side. The idea would be that the server worker thread is interrupted when the read timeout elapses, so that it becomes available for other tasks. When I try to set the read timeout as follows I get an "unsupported channel option" warning at start-up:
serverBootstrap.childOption(ChannelOption.SO_TIMEOUT, 30000);
Is there a way to achieve a "read/processing timeout" on the server-side of things? Any help is appreciated.
Kind Regards,
Michael
Add a ReadTimeoutHandler to the first position of your pipeline:
http://netty.io/4.0/api/io/netty/handler/timeout/ReadTimeoutHandler.html
public class ReadTimeoutHandler extends ChannelInboundHandlerAdapter
// Raises a ReadTimeoutException when no data was read within a certain period of time.
// The connection is closed when there is no inbound traffic
// for 30 seconds.
public class MyChannelInitializer extends ChannelInitializer<Channel> {
public void initChannel(Channel channel) {
channel.pipeline().addLast("readTimeoutHandler", new ReadTimeoutHandler(30);
channel.pipeline().addLast("myHandler", new MyHandler());
}
}
// Handler should handle the ReadTimeoutException.
public class MyHandler extends ChannelDuplexHandler {
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
if (cause instanceof ReadTimeoutException) {
// do something
} else {
super.exceptionCaught(ctx, cause);
}
}
}
ServerBootstrap bootstrap = ...;
...
bootstrap.childHandler(new MyChannelInitializer());
...
Related
I have a concurrent issue, my WebSocket was used spring-message,
when my chatroom has a lot of people it will very slow.
So I try to find how, and I found some problem where the WebSocketSession using sendMessage, it has a synchronized in class websocketServerSockJsSession
#Override
public void sendMessageInternal(String message) throws SockJsTransportFailureException {
// Open frame not sent yet?
// If in the session initialization thread, then cache, otherwise wait.
if (!this.openFrameSent) {
synchronized (this.initSessionLock) {
if (!this.openFrameSent) {
this.initSessionCache.add(message);
return;
}
}
}
so if they have 200 chat in one second it will be very slow,
I found the implement of WebSocketSession call ConcurrentWebSocketSessionDecorator.
But I can't cast WebSocketServerSockJsSession to ConcurrentWebSocketSessionDecorator, I can't find how to set my WebSocketSession.
I can't change the sockJS.
So how can I do if I use the sockJS and I want to use ConcurrentWebSocketSessionDecorator method?
is another way to implement the ConcurrentWebSocketSessionDecorator sendMessage or I can do some property setting and make my WebSocketSession turn to ConcurrentWebSocketSessionDecorator?
this my config setting
#Configuration
#EnableWebMvc
#EnableWebSocket
public class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler(), "/websocket/send").addInterceptors(new HandshakeInterceptor()).setAllowedOrigins("*");
registry.addHandler(webSocketHandler(), "/websocket/sockjs").addInterceptors(new HandshakeInterceptor()).setAllowedOrigins("*").withSockJS();
}
As its name suggests, the ConcurrentWebSocketSessionDecorator is a Decorator.
This decorator overrides some functions such as sendMessage of WebSocketSession, and WebSocketServerSockJSession performs its actions through its webSocketSession, so changing webSocketSession to ConcurrentWebSocketSessionDecorator can solve the problem.
ConcurrentWebSocketSessionDecorator currentWebSocketSessionDecorator = new ConcurrentWebSocketSessionDecorator (session, 1000, 1024);
wsSockJsSession.initializeDelegateSession((WebSocketSession)concurrentWebSocketSessionDecorator);
I am trying to run heavy tasks asynchronously. The client then polls the server to know when the job is done. This seemed to work, but I noticed that my WebService that responds to the polling is blocked when I put a breakpoint in my #Asynchronous Method.
This is what I did:
JobWS.java // Used to start a job
#RequestScoped
#Path("/job")
#Produces(MediaType.APPLICATION_JSON)
public class JobWS {
#POST
#Path("/run/create")
public Response startJob(MyDTO dto) {
return ResponseUtil.ok(jobService.createJob(dto));
}
}
JobService.java // Creates the job in the DB, starts it and returns its ID
#Stateless
public class JobService {
#Inject
private AsyncJobService asyncJobService;
#Inject
private Worker worker;
public AsyncJob createJob(MyDTO dto) {
AsyncJob asyncJob = asyncJobService.create();
worker.doWork(asyncJob.getId(), dto);
return asyncJob; // With this, the client can poll the job with its ID
}
}
Worker.java // Working hard
#Stateless
public class Worker {
#Asynchronous
public void doWork(UUID asyncJobId, MyDTO dto) {
// Do work
// ...
// Eventually update the AsyncJob and mark it as finished
}
}
Finally, my Polling Webservice, which is the one being blocked
#RequestScoped
#Path("/polling")
#Produces(MediaType.APPLICATION_JSON)
public class PollingWS {
#Inject
AsyncJobService asyncJobService;
#GET
#Path("/{id}")
public Response loadAsyncJob(#PathParam("id") #NotNull UUID id) {
return ResponseUtil.ok(asyncJobService.loadAsyncJob(id));
}
}
If I put a breakpoint somwhere in doWork(), the PollingWS does not respond to HTTP requests anymore. When I debug through doWork(), occasionally I get a response, but only when jumping from one breakpoint to another, never when waiting at a breakpoint.
What am I missing here ? Why is my doWork() method blocking my Webservice, despite it running asynchronously ?
I found the culprit. A breakpoint suspends all threads by default. In IntelliJ, a right click on it will open the following dialog:
When changing the "Suspend" property to "Thread", my WS is not blocked anymore and everything works as expected. In retrospect, I feel a bit stupid for asking this. But hey... maybe it will help others :)
I m sending several retrofit calls via SyncAdapter onPerformSync and I m trying to regulate http calls by sending out via a try/catch sleep statement. However, this is blocking the UI and will be not responsive only after all calls are done.
What is a better way to regulate network calls (with a sleep timer) in background in onPerformSync without blocking UI?
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
String baseUrl = BuildConfig.API_BASE_URL;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
service = retrofit.create(HTTPService.class);
Call<RetroFitModel> RetroFitModelCall = service.getRetroFit(apiKey, sortOrder);
RetroFitModelCall.enqueue(new Callback<RetroFitModel>() {
#Override
public void onResponse(Response<RetroFitModel> response) {
if (!response.isSuccess()) {
} else {
List<RetroFitResult> retrofitResultList = response.body().getResults();
Utility.storeList(getContext(), retrofitResultList);
for (final RetroFitResult result : retrofitResultList) {
RetroFitReview(result.getId(), service);
try {
// Sleep for SLEEP_TIME before running RetroFitReports & RetroFitTime
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
}
RetroFitReports(result.getId(), service);
RetroFitTime(result.getId(), service);
}
}
}
#Override
public void onFailure(Throwable t) {
Log.e(LOG_TAG, "Error: " + t.getMessage());
}
});
}
}
The "onPerformSync" code is executed within the "SyncAdapterThread" thread, not within the Main UI thread. However this could change when making asynchronous calls with callbacks (which is our case here).
Here you are using an asynchronous call of the Retrofit "call.enqueue" method, and this has an impact on thread execution. The question we need to ask at this point:
Where callback methods are going to be executed?
To get the answer to this question, we have to determine which Looper is going to be used by the Handler that will post callbacks.
In case we are playing with handlers ourselves, we can define the looper, the handler and how to process messages/runnables between handlers. But this time it is different because we are using a third party framework (Retrofit). So we have to know which looper used by Retrofit?
Please note that if Retrofit didn't already define his looper, you
could have caught an exception saying that you need a looper to
process callbacks. In other words, an asynchronous call needs to be in
a looper thread in order to post callbacks back to the thread from
where it was executed.
According to the code source of Retrofit (Platform.java):
static class Android extends Platform {
#Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor == null) {
callbackExecutor = new MainThreadExecutor();
}
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
#Override public void execute(Runnable r) {
handler.post(r);
}
}
}
You can notice "Looper.getMainLooper()", which means that Retrofit will post messages/runnables into the main thread message queue (you can do research on this for further detailed explanation). Thus the posted message/runnable will be handled by the main thread.
So that being said, the onResponse/onFailure callbacks will be executed in the main thread. And it's going to block the UI, if you are doing too much work (Thread.sleep(SLEEP_TIME);). You can check it by yourself: just make a breakpoint in "onResponse" callback and check in which thread it is running.
So how to handle this situation? (the answer to your question about Retrofit use)
Since we are already in a background thread (SyncAdapterThread), so there is no need to make asynchronous calls in your case. Just make a Retrofit synchronous call and then process the result, or log a failure. This way, you will not block the UI.
I searched a lot about implementing WebSocket/XMPP on Spring MVC based server but couldn't reach to a concrete answer. So here is my requirement
Receive a message from a client (in my case it will be a android/iOS mobile) via WebSocket/XMPP on tomcat server and parse the actual message at server side
Send a message from server app to WebSocket/XMPP client
If somebody could help me to point on some good tutorial or demo code, it would be a great help.
run Tomee 1.5.2
http://openejb.apache.org/downloads.html
activate the ActiveMQ JMS Server. create an OpenEJB configuration.
http://www.mail-archive.com/users#openejb.apache.org/msg04327.html
setup an XMPP ActiveMQ server protocol listener (in the activemq.xml)
in your Spring services configuration, create a Spring JMS listener (Spring ListenerContainer) configuration on the Topic/Queue.
you can use the JmsTemplate to push a message out to the Queue/Topic via ActiveMQ, the XMPP client will receive the message.
Enjoy!
BTW: This is exactly what I am in the middle of setting up right now...still learning.
check this out: www.xchat.io. It was built based on Asynchronous Spring MVC (DefferredResult, you know), XMPP, and jQuery. it's promising.
I am not sure if this is just perfect way to achieve or not, but for now I have found a solution and it would be glad to share it here.
There are two steps that you have to done.
1. Instead of ordinary HTTPServlet sub class, create a sub class of WebSocketServlet and
2. Create a sub class of MessageInbound class and override its required methods.
P.S. : Only latest version of tomcat supports WebSocket (apache tomcat 7.0.42 or higher).
Here is a WebSocket class.
public class WsChatServlet extends WebSocketServlet {
private static final long serialVersionUID = 1456546233L;
#Override
protected StreamInbound createWebSocketInbound(String protocol,
HttpServletRequest request) {
return new IncomingMessageHandler();
}
}
And this is a simple class which can send/receive message (String/binary).
public class IncomingMessageHandler extends MessageInbound {
#Override
public void onOpen(WsOutbound outbound) {
logger.info("Open Client.");
}
#Override
public void onClose(int status) {
logger.info("Close Client.");
}
#Override
public void onTextMessage(CharBuffer cb) throws IOException {
logger.info("Text Message received:" + cb.toString());
}
#Override
public void onBinaryMessage(ByteBuffer bb) throws IOException {
}
public synchronized void sendTextMessage(String message) {
try {
CharBuffer buffer = CharBuffer.wrap(message);
this.getMyoutbound().writeTextMessage(buffer);
this.getMyoutbound().flush();
} catch (IOException e) {
// Handle Exception
}
}
}
I am developing custom HTTP server with netty 3.3.1.
I need to implement something like this
HTTP Server receives request
HTTP Server parses it and invokes HTTP request as a client to other machine
HTTP Server waits for the response of request sent in (2)
HTTP Server sends response to request from (1) based on what had received in (3)
It means that client request (2) has to behave as synchronous.
What I wrote is based on HttpSnoopClient example but it does not work, because I receive
java.lang.IllegalStateException:
await*() in I/O thread causes a dead lock or sudden performance drop. Use addListener() instead or call await*() from a different thread.
I've refactored the code from the example mentioned above and now it looks more less like this (starting from line 7f of HttpSnoopClient):
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
if (!future.isSuccess()) {
System.err.println("Cannot connect");
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return;
}
System.err.println("Connected");
Channel channel = future.getChannel();
// Send the HTTP request.
channel.write(request);
channel.close();
// Wait for the server to close the connection.
channel.getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
System.err.println("Disconnected");
bootstrap.releaseExternalResources(); // DOES NOT WORK?
}
});
}
});
}
}
The run() command from the above example is invoked in the messageReceived function of my herver handler.
So it became asynchronous and avoid await* functions. Request is invoked properly. But - for uknown reason for me - the line
bootstrap.releaseExternalResources(); // DOES NOT WORK?
does not work. It throws an exception saying that I cannot kill the thread I am currently using (which sounds reasonable, but still does not give me an answer how to do that in a different way).
I am also not sure is this a correct approach?
Maybe you can recommend a tutorial of such event programming techniques in netty? How to deal - in general - with a few asynchronous requests that has to be invoked in specified order and wait for each other?
Thank you,
If you really want to release the bootstrap on close you can do it like this:
channel.getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
System.err.println("Disconnected");
new Thread(new Runnable() {
public void run() {
bootstrap.releaseExternalResources();
}
}).start();
}
});