github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/runtime/runtime.go (about) 1 // Copyright 2011 Google Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 /* 6 Package runtime exposes information about the resource usage of the application. 7 It also provides a way to run code in a new background context of a module. 8 9 This package does not work on Managed VMs. 10 */ 11 package runtime 12 13 import ( 14 "net/http" 15 16 "golang.org/x/net/context" 17 18 "google.golang.org/appengine" 19 "google.golang.org/appengine/internal" 20 pb "google.golang.org/appengine/internal/system" 21 ) 22 23 // Statistics represents the system's statistics. 24 type Statistics struct { 25 // CPU records the CPU consumed by this instance, in megacycles. 26 CPU struct { 27 Total float64 28 Rate1M float64 // consumption rate over one minute 29 Rate10M float64 // consumption rate over ten minutes 30 } 31 // RAM records the memory used by the instance, in megabytes. 32 RAM struct { 33 Current float64 34 Average1M float64 // average usage over one minute 35 Average10M float64 // average usage over ten minutes 36 } 37 } 38 39 func Stats(c context.Context) (*Statistics, error) { 40 req := &pb.GetSystemStatsRequest{} 41 res := &pb.GetSystemStatsResponse{} 42 if err := internal.Call(c, "system", "GetSystemStats", req, res); err != nil { 43 return nil, err 44 } 45 s := &Statistics{} 46 if res.Cpu != nil { 47 s.CPU.Total = res.Cpu.GetTotal() 48 s.CPU.Rate1M = res.Cpu.GetRate1M() 49 s.CPU.Rate10M = res.Cpu.GetRate10M() 50 } 51 if res.Memory != nil { 52 s.RAM.Current = res.Memory.GetCurrent() 53 s.RAM.Average1M = res.Memory.GetAverage1M() 54 s.RAM.Average10M = res.Memory.GetAverage10M() 55 } 56 return s, nil 57 } 58 59 /* 60 RunInBackground makes an API call that triggers an /_ah/background request. 61 62 There are two independent code paths that need to make contact: 63 the RunInBackground code, and the /_ah/background handler. The matchmaker 64 loop arranges for the two paths to meet. The RunInBackground code passes 65 a send to the matchmaker, the /_ah/background passes a recv to the matchmaker, 66 and the matchmaker hooks them up. 67 */ 68 69 func init() { 70 http.HandleFunc("/_ah/background", handleBackground) 71 72 sc := make(chan send) 73 rc := make(chan recv) 74 sendc, recvc = sc, rc 75 go matchmaker(sc, rc) 76 } 77 78 var ( 79 sendc chan<- send // RunInBackground sends to this 80 recvc chan<- recv // handleBackground sends to this 81 ) 82 83 type send struct { 84 id string 85 f func(context.Context) 86 } 87 88 type recv struct { 89 id string 90 ch chan<- func(context.Context) 91 } 92 93 func matchmaker(sendc <-chan send, recvc <-chan recv) { 94 // When one side of the match arrives before the other 95 // it is inserted in the corresponding map. 96 waitSend := make(map[string]send) 97 waitRecv := make(map[string]recv) 98 99 for { 100 select { 101 case s := <-sendc: 102 if r, ok := waitRecv[s.id]; ok { 103 // meet! 104 delete(waitRecv, s.id) 105 r.ch <- s.f 106 } else { 107 // waiting for r 108 waitSend[s.id] = s 109 } 110 case r := <-recvc: 111 if s, ok := waitSend[r.id]; ok { 112 // meet! 113 delete(waitSend, r.id) 114 r.ch <- s.f 115 } else { 116 // waiting for s 117 waitRecv[r.id] = r 118 } 119 } 120 } 121 } 122 123 var newContext = appengine.NewContext // for testing 124 125 func handleBackground(w http.ResponseWriter, req *http.Request) { 126 id := req.Header.Get("X-AppEngine-BackgroundRequest") 127 128 ch := make(chan func(context.Context)) 129 recvc <- recv{id, ch} 130 (<-ch)(newContext(req)) 131 } 132 133 // RunInBackground runs f in a background goroutine in this process. 134 // f is provided a context that may outlast the context provided to RunInBackground. 135 // This is only valid to invoke from a manually scaled module. 136 func RunInBackground(c context.Context, f func(c context.Context)) error { 137 req := &pb.StartBackgroundRequestRequest{} 138 res := &pb.StartBackgroundRequestResponse{} 139 if err := internal.Call(c, "system", "StartBackgroundRequest", req, res); err != nil { 140 return err 141 } 142 sendc <- send{res.GetRequestId(), f} 143 return nil 144 } 145 146 func init() { 147 internal.RegisterErrorCodeMap("system", pb.SystemServiceError_ErrorCode_name) 148 }