Source file
doc/codewalk/urlpoll.go
1
2
3
4
5 package main
6
7 import (
8 "log"
9 "net/http"
10 "time"
11 )
12
13 const (
14 numPollers = 2
15 pollInterval = 60 * time.Second
16 statusInterval = 10 * time.Second
17 errTimeout = 10 * time.Second
18 )
19
20 var urls = []string{
21 "http://www.google.com/",
22 "http://golang.org/",
23 "http://blog.golang.org/",
24 }
25
26
27 type State struct {
28 url string
29 status string
30 }
31
32
33
34
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
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
61 type Resource struct {
62 url string
63 errCount int
64 }
65
66
67
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
80
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
96 pending, complete := make(chan *Resource), make(chan *Resource)
97
98
99 status := StateMonitor(statusInterval)
100
101
102 for i := 0; i < numPollers; i++ {
103 go Poller(pending, complete, status)
104 }
105
106
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