Source file doc/codewalk/urlpoll.go

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"log"
     9  	"net/http"
    10  	"time"
    11  )
    12  
    13  const (
    14  	numPollers     = 2                // number of Poller goroutines to launch
    15  	pollInterval   = 60 * time.Second // how often to poll each URL
    16  	statusInterval = 10 * time.Second // how often to log status to stdout
    17  	errTimeout     = 10 * time.Second // back-off timeout on error
    18  )
    19  
    20  var urls = []string{
    21  	"http://www.google.com/",
    22  	"http://golang.org/",
    23  	"http://blog.golang.org/",
    24  }
    25  
    26  // State represents the last-known state of a URL.
    27  type State struct {
    28  	url    string
    29  	status string
    30  }
    31  
    32  // StateMonitor maintains a map that stores the state of the URLs being
    33  // polled, and prints the current state every updateInterval nanoseconds.
    34  // It returns a chan State to which resource state should be sent.
    35  func StateMonitor(updateInterval time.Duration) chan<- State {
    36  	updates := make(chan State)
    37  	urlStatus := make(map[string]string)
    38  	ticker := time.NewTicker(updateInterval)
    39  	go func() {
    40  		for {
    41  			select {
    42  			case <-ticker.C:
    43  				logState(urlStatus)
    44  			case s := <-updates:
    45  				urlStatus[s.url] = s.status
    46  			}
    47  		}
    48  	}()
    49  	return updates
    50  }
    51  
    52  // logState prints a state map.
    53  func logState(s map[string]string) {
    54  	log.Println("Current state:")
    55  	for k, v := range s {
    56  		log.Printf(" %s %s", k, v)
    57  	}
    58  }
    59  
    60  // Resource represents an HTTP URL to be polled by this program.
    61  type Resource struct {
    62  	url      string
    63  	errCount int
    64  }
    65  
    66  // Poll executes an HTTP HEAD request for url
    67  // and returns the HTTP status string or an error string.
    68  func (r *Resource) Poll() string {
    69  	resp, err := http.Head(r.url)
    70  	if err != nil {
    71  		log.Println("Error", r.url, err)
    72  		r.errCount++
    73  		return err.Error()
    74  	}
    75  	r.errCount = 0
    76  	return resp.Status
    77  }
    78  
    79  // Sleep sleeps for an appropriate interval (dependent on error state)
    80  // before sending the Resource to done.
    81  func (r *Resource) Sleep(done chan<- *Resource) {
    82  	time.Sleep(pollInterval + errTimeout*time.Duration(r.errCount))
    83  	done <- r
    84  }
    85  
    86  func Poller(in <-chan *Resource, out chan<- *Resource, status chan<- State) {
    87  	for r := range in {
    88  		s := r.Poll()
    89  		status <- State{r.url, s}
    90  		out <- r
    91  	}
    92  }
    93  
    94  func main() {
    95  	// Create our input and output channels.
    96  	pending, complete := make(chan *Resource), make(chan *Resource)
    97  
    98  	// Launch the StateMonitor.
    99  	status := StateMonitor(statusInterval)
   100  
   101  	// Launch some Poller goroutines.
   102  	for i := 0; i < numPollers; i++ {
   103  		go Poller(pending, complete, status)
   104  	}
   105  
   106  	// Send some Resources to the pending queue.
   107  	go func() {
   108  		for _, url := range urls {
   109  			pending <- &Resource{url: url}
   110  		}
   111  	}()
   112  
   113  	for r := range complete {
   114  		go r.Sleep(pending)
   115  	}
   116  }
   117  

View as plain text