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