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/* 6Package runtime exposes information about the resource usage of the application. 7It also provides a way to run code in a new background context of a module. 8 9This package does not work on App Engine "flexible environment". 10*/ 11package runtime // import "google.golang.org/appengine/runtime" 12 13import ( 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. 24type 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 39func 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/* 60RunInBackground makes an API call that triggers an /_ah/background request. 61 62There are two independent code paths that need to make contact: 63the RunInBackground code, and the /_ah/background handler. The matchmaker 64loop arranges for the two paths to meet. The RunInBackground code passes 65a send to the matchmaker, the /_ah/background passes a recv to the matchmaker, 66and the matchmaker hooks them up. 67*/ 68 69func 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 78var ( 79 sendc chan<- send // RunInBackground sends to this 80 recvc chan<- recv // handleBackground sends to this 81) 82 83type send struct { 84 id string 85 f func(context.Context) 86} 87 88type recv struct { 89 id string 90 ch chan<- func(context.Context) 91} 92 93func 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 123var newContext = appengine.NewContext // for testing 124 125func 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 service set to basic or manual scaling. 136func 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 146func init() { 147 internal.RegisterErrorCodeMap("system", pb.SystemServiceError_ErrorCode_name) 148} 149