From 7aab87b272b846d6997dddbc35a3389620d92509 Mon Sep 17 00:00:00 2001
From: Mark McGranaghan <mmcgrana@gmail.com>
Date: Thu, 11 Oct 2012 12:40:23 -0700
Subject: [PATCH] publish timeouts

---
 examples.txt                  |  2 +-
 examples/timeouts/timeouts.go | 49 ++++++++++++++++++++++++++---------
 examples/timeouts/timeouts.sh | 11 ++++++++
 3 files changed, 49 insertions(+), 13 deletions(-)
 create mode 100644 examples/timeouts/timeouts.sh

diff --git a/examples.txt b/examples.txt
index c2446fb..896170b 100644
--- a/examples.txt
+++ b/examples.txt
@@ -32,7 +32,7 @@ Channels
 # Channel Directions
 # Synchronization
 Select
-# Timeouts
+Timeouts
 # Scatter Gather
 # Rate Limiting
 # Worker Pools
diff --git a/examples/timeouts/timeouts.go b/examples/timeouts/timeouts.go
index fda81b9..96773dc 100644
--- a/examples/timeouts/timeouts.go
+++ b/examples/timeouts/timeouts.go
@@ -1,25 +1,50 @@
+// _Timeouts_ are important for programs that connect to
+// external resources or that otherwise need to bound
+// execution time. Implementing timeouts in Go is easy and
+// elegant thanks to channels and `select`.
+
 package main
 
 import "time"
 import "fmt"
 
 func main() {
-    c := make(chan string)
-    d := make(chan bool, 1)
 
+    // For our example, suppose we're execting an external
+    // call that returns its result on a channel `c1`
+    // after 2s.
+    c1 := make(chan string)
     go func() {
-        time.Sleep(time.Millisecond * 1500)
-        c <- "ready"
+        time.Sleep(time.Second * 2)
+        c1 <- "result 1"
     }()
 
+    // Here's the `select` implementing a timeout.
+    // `res := <-c1` awaits the result and `<-Time.After`
+    // awaits a value to be sent after the timeout of
+    // 1s. Since `select` proceeds with the first
+    // receive that's ready, we'll take the timeout case
+    // if the operation takes more than the allowed 1000ms.
+    select {
+    case res := <-c1:
+        fmt.Println(res)
+    case <-time.After(time.Second * 1):
+        fmt.Println("timeout 1")
+    }
+
+    // If we allow a longer timeout of 3s, then the receive
+    // from `c2` will succeed and we'll print the result.
+    c2 := make(chan string)
     go func() {
-        select {
-        case msg := <-c:
-            fmt.Println(msg)
-        case <-time.After(time.Millisecond * 1000):
-            fmt.Println("timeout")
-        }
-        d <- true
+        time.Sleep(time.Second * 2)
+        c2 <- "result 2"
     }()
-    <-d
+    select {
+    case res := <-c2:
+        fmt.Println(res)
+    case <-time.After(time.Second * 3):
+        fmt.Println("timeout 2")
+    }
 }
+
+// todo: cancellation?
diff --git a/examples/timeouts/timeouts.sh b/examples/timeouts/timeouts.sh
new file mode 100644
index 0000000..8a9dfb4
--- /dev/null
+++ b/examples/timeouts/timeouts.sh
@@ -0,0 +1,11 @@
+# Running this program shows the first operation timing
+# out and the second succeeding.
+$ go run timeouts.go 
+timeout 1
+result 2
+
+# Using this `select` timeout pattern requires
+# communicating results over channels. This is a good
+# idea in general because other important Go features are
+# based on channels and `select`. We'll look at two
+# examples of this next: timers and tickers.