PageRenderTime 33ms CodeModel.GetById 21ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 1ms

/hudson-core/src/main/java/hudson/node_monitors/ResponseTimeMonitor.java

http://github.com/hudson/hudson
Java | 173 lines | 98 code | 17 blank | 58 comment | 10 complexity | 88c4bf44657df41c32de8197552d9348 MD5 | raw file
  1/*
  2 * The MIT License
  3 * 
  4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Red Hat, Inc.
  5 * 
  6 * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 * of this software and associated documentation files (the "Software"), to deal
  8 * in the Software without restriction, including without limitation the rights
  9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10 * copies of the Software, and to permit persons to whom the Software is
 11 * furnished to do so, subject to the following conditions:
 12 * 
 13 * The above copyright notice and this permission notice shall be included in
 14 * all copies or substantial portions of the Software.
 15 * 
 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22 * THE SOFTWARE.
 23 */
 24package hudson.node_monitors;
 25
 26import hudson.Util;
 27import hudson.Extension;
 28import hudson.model.Descriptor.FormException;
 29import hudson.slaves.OfflineCause;
 30import hudson.model.Computer;
 31import hudson.remoting.Callable;
 32import hudson.remoting.Future;
 33import hudson.util.TimeUnit2;
 34import hudson.util.IOException2;
 35import net.sf.json.JSONObject;
 36import org.kohsuke.stapler.StaplerRequest;
 37
 38import java.io.IOException;
 39import java.util.concurrent.ExecutionException;
 40import java.util.concurrent.TimeUnit;
 41import java.util.concurrent.TimeoutException;
 42import java.util.logging.Logger;
 43import org.kohsuke.stapler.export.Exported;
 44import org.kohsuke.stapler.export.ExportedBean;
 45
 46/**
 47 * Monitors the round-trip response time to this slave.
 48 *
 49 * @author Kohsuke Kawaguchi
 50 */
 51public class ResponseTimeMonitor extends NodeMonitor {
 52    @Extension
 53    public static final AbstractNodeMonitorDescriptor<Data> DESCRIPTOR = new AbstractNodeMonitorDescriptor<Data>() {
 54        protected Data monitor(Computer c) throws IOException, InterruptedException {
 55            Data old = get(c);
 56            Data d;
 57
 58            long start = System.nanoTime();
 59            Future<String> f = c.getChannel().callAsync(new NoopTask());
 60            try {
 61                f.get(TIMEOUT, TimeUnit.MILLISECONDS);
 62                long end = System.nanoTime();
 63                d = new Data(old,TimeUnit2.NANOSECONDS.toMillis(end-start));
 64            } catch (ExecutionException e) {
 65                throw new IOException2(e.getCause());    // I don't think this is possible
 66            } catch (TimeoutException e) {
 67                // special constant to indicate that the processing timed out.
 68                d = new Data(old,-1L);
 69            }
 70
 71            if(d.hasTooManyTimeouts() && !isIgnored()) {
 72                // unlike other monitors whose failure still allow us to communicate with the slave,
 73                // the failure in this monitor indicates that we are just unable to make any requests
 74                // to this slave. So we should severe the connection, as opposed to marking it temporarily
 75                // off line, which still keeps the underlying channel open.
 76                c.disconnect(d);
 77                LOGGER.warning(Messages.ResponseTimeMonitor_MarkedOffline(c.getName()));
 78            }
 79            return d;
 80        }
 81
 82        public String getDisplayName() {
 83            return Messages.ResponseTimeMonitor_DisplayName();
 84        }
 85
 86        @Override
 87        public NodeMonitor newInstance(StaplerRequest req, JSONObject formData) throws FormException {
 88            return new ResponseTimeMonitor();
 89        }
 90    };
 91
 92    /**
 93     * Immutable representation of the monitoring data.
 94     */
 95    @ExportedBean
 96    public static final class Data extends OfflineCause {
 97        /**
 98         * Record of the past 5 times. -1 if time out. Otherwise in milliseconds.
 99         * Old ones first.
100         */
101        private final long[] past5;
102
103        private Data(Data old, long newDataPoint) {
104            if(old==null)
105                past5 = new long[] {newDataPoint};
106            else {
107                past5 = new long[Math.min(5,old.past5.length+1)];
108                int copyLen = past5.length - 1;
109                System.arraycopy(old.past5, old.past5.length-copyLen, this.past5, 0, copyLen);
110                past5[past5.length-1] = newDataPoint;
111            }
112        }
113
114        /**
115         * Computes the recurrence of the time out
116         */
117        private int failureCount() {
118            int cnt=0;
119            for(int i=past5.length-1; i>=0 && past5[i]<0; i--, cnt++)
120                ;
121            return cnt;
122        }
123
124        /**
125         * Computes the average response time, by taking the time out into account.
126         */
127        @Exported
128        public long getAverage() {
129            long total=0;
130            for (long l : past5) {
131                if(l<0)     total += TIMEOUT;
132                else        total += l;
133            }
134            return total/past5.length;
135        }
136
137        public boolean hasTooManyTimeouts() {
138            return failureCount()>=5;
139        }
140
141        /**
142         * HTML rendering of the data
143         */
144        @Override
145        public String toString() {
146//            StringBuilder buf = new StringBuilder();
147//            for (long l : past5) {
148//                if(buf.length()>0)  buf.append(',');
149//                buf.append(l);
150//            }
151//            return buf.toString();
152            int fc = failureCount();
153            if(fc>0)
154                return Util.wrapToErrorSpan(Messages.ResponseTimeMonitor_TimeOut(fc));
155            return getAverage()+"ms";
156        }
157    }
158
159    private static class NoopTask implements Callable<String,RuntimeException> {
160        public String call() {
161            return null;
162        }
163
164        private static final long serialVersionUID = 1L;
165    }
166
167    /**
168     * Time out interval in milliseconds.
169     */
170    private static final long TIMEOUT = 5000;
171
172    private static final Logger LOGGER = Logger.getLogger(ResponseTimeMonitor.class.getName());
173}