github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/doc/codewalk/urlpoll.go (about) 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 }