123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- // 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)
- }
- }
|