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