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  }