package com.leansoft.luxun.server; import java.io.Closeable; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.thrift.TProcessor; import org.apache.thrift.protocol.TBinaryProtocol; //import org.apache.thrift.server.THsHaServer; import org.apache.thrift.server.TNonblockingServer; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TNonblockingServerSocket; import org.apache.thrift.transport.TTransportException; import com.leansoft.luxun.api.generated.QueueService; import com.leansoft.luxun.mx.ThriftServerStats; import com.leansoft.luxun.utils.Utils; public class ThriftServer implements Closeable { private static final Logger logger = LoggerFactory.getLogger(ThriftServer.class); private final QueueService.Iface queueService; private final ServerConfig serverConfig; private final ThriftServerStats stats; private final TNonblockingServer server; private final ServerThread serverThread; public final static int CLOSE_TIMEOUT_IN_SECONDS = 30; // seconds public final static int STARTUP_TIMEOUT_IN_SECONDS = 30; // seconds public ThriftServer(QueueService.Iface queueService, ServerConfig serverConfig, ThriftServerStats stats) throws TTransportException { this.queueService = queueService; this.serverConfig = serverConfig; this.stats = stats; // assemble thrift server TProcessor tprocessor = new QueueService.Processor(this.queueService); TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(serverConfig.getPort()); TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(tnbSocketTransport); tnbArgs.processor(tprocessor); // Nonblocking server mode must use TFramedTransport tnbArgs.transportFactory(new TFramedTransport.Factory()); tnbArgs.protocolFactory(new TBinaryProtocol.Factory()); this.server = new TNonblockingServer(tnbArgs); // THsHaServer.Args thhArgs = new THsHaServer.Args(tnbSocketTransport); // thhArgs.processor(tprocessor); // // Nonblocking server mode must use TFramedTransport // thhArgs.transportFactory(new TFramedTransport.Factory()); // thhArgs.protocolFactory(new TBinaryProtocol.Factory()); // // this.server = new THsHaServer(thhArgs); this.serverThread = new ServerThread(this.server); } @Override public void close() throws IOException { this.server.stop(); int timeWaited = 0; int checkInterval = 1000; while(!this.server.isStopped() || this.server.isServing()) { if (timeWaited > CLOSE_TIMEOUT_IN_SECONDS * 1000) { String errorMessage = "fail to stop server within timeout " + CLOSE_TIMEOUT_IN_SECONDS + " seconds"; logger.error(errorMessage); throw new RuntimeException(errorMessage); } try { Thread.sleep(checkInterval); timeWaited += checkInterval; } catch (InterruptedException e) { // ignore } logger.info("Wating server to close, time waited : " + timeWaited / 1000 + " s."); } logger.info("Thrift server closed."); } public void startup() { Utils.newThread("luxun-server", this.serverThread, false).start(); int timeWaited = 0; int checkInterval = 1000; while(!this.server.isServing() && !this.serverThread.isFailed()) { logger.info("Wating server to start, time waited : " + timeWaited / 1000 + " s."); if (timeWaited > STARTUP_TIMEOUT_IN_SECONDS * 1000) { String errorMessage = "fail to start server within timeout " + STARTUP_TIMEOUT_IN_SECONDS + " seconds"; logger.error(errorMessage); throw new RuntimeException(errorMessage); } try { Thread.sleep(checkInterval); timeWaited += checkInterval; } catch (InterruptedException e) { // ignore } } if (this.serverThread.isFailed()) { logger.info("Thrift server fail to start on port : " + this.serverConfig.getPort()); } else { logger.info("Thrift server started on port : " + this.serverConfig.getPort()); } } public ThriftServerStats getStats() { return stats; } static class ServerThread implements Runnable { private TNonblockingServer server; private AtomicBoolean failed = new AtomicBoolean(false); ServerThread(TNonblockingServer server) { this.server = server; } @Override public void run() { try { this.server.serve(); } catch (Exception e) { failed.set(true); logger.error("Thrift server fail to start", e); } } public boolean isFailed() { return failed.get(); } } }