/* * Copyright 1999-2012 Alibaba Group. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.remoting.exchange.support.header; import java.util.Collection; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.remoting.Channel; import com.alibaba.dubbo.remoting.Client; import com.alibaba.dubbo.remoting.exchange.Request; /** * @author <a href="mailto:gang.lvg@alibaba-inc.com">kimi</a> */ final class HeartBeatTask implements Runnable { private static final Logger logger = LoggerFactory.getLogger( HeartBeatTask.class ); private ChannelProvider channelProvider; private int heartbeat; private int heartbeatTimeout; HeartBeatTask( ChannelProvider provider, int heartbeat, int heartbeatTimeout ) { this.channelProvider = provider; this.heartbeat = heartbeat; this.heartbeatTimeout = heartbeatTimeout; } public void run() { try { long now = System.currentTimeMillis(); for ( Channel channel : channelProvider.getChannels() ) { if (channel.isClosed()) { continue; } try { Long lastRead = ( Long ) channel.getAttribute( HeaderExchangeHandler.KEY_READ_TIMESTAMP ); Long lastWrite = ( Long ) channel.getAttribute( HeaderExchangeHandler.KEY_WRITE_TIMESTAMP ); if ( ( lastRead != null && now - lastRead > heartbeat ) || ( lastWrite != null && now - lastWrite > heartbeat ) ) { Request req = new Request(); req.setVersion( "2.0.0" ); req.setTwoWay( true ); req.setEvent( Request.HEARTBEAT_EVENT ); channel.send( req ); if ( logger.isDebugEnabled() ) { logger.debug( "Send heartbeat to remote channel " + channel.getRemoteAddress() + ", cause: The channel has no data-transmission exceeds a heartbeat period: " + heartbeat + "ms" ); } } if ( lastRead != null && now - lastRead > heartbeatTimeout ) { logger.warn( "Close channel " + channel + ", because heartbeat read idle time out: " + heartbeatTimeout + "ms" ); if (channel instanceof Client) { try { ((Client)channel).reconnect(); }catch (Exception e) { //do nothing } } else { channel.close(); } } } catch ( Throwable t ) { logger.warn( "Exception when heartbeat to remote channel " + channel.getRemoteAddress(), t ); } } } catch ( Throwable t ) { logger.warn( "Unhandled exception when heartbeat, cause: " + t.getMessage(), t ); } } interface ChannelProvider { Collection<Channel> getChannels(); } }