123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // Copyright 2011 Google Inc. All rights reserved.
- // Use of this source code is governed by the Apache 2.0
- // license that can be found in the LICENSE file.
- /*
- Package runtime exposes information about the resource usage of the application.
- It also provides a way to run code in a new background context of a module.
- This package does not work on Managed VMs.
- */
- package runtime // import "google.golang.org/appengine/runtime"
- import (
- "net/http"
- "golang.org/x/net/context"
- "google.golang.org/appengine"
- "google.golang.org/appengine/internal"
- pb "google.golang.org/appengine/internal/system"
- )
- // Statistics represents the system's statistics.
- type Statistics struct {
- // CPU records the CPU consumed by this instance, in megacycles.
- CPU struct {
- Total float64
- Rate1M float64 // consumption rate over one minute
- Rate10M float64 // consumption rate over ten minutes
- }
- // RAM records the memory used by the instance, in megabytes.
- RAM struct {
- Current float64
- Average1M float64 // average usage over one minute
- Average10M float64 // average usage over ten minutes
- }
- }
- func Stats(c context.Context) (*Statistics, error) {
- req := &pb.GetSystemStatsRequest{}
- res := &pb.GetSystemStatsResponse{}
- if err := internal.Call(c, "system", "GetSystemStats", req, res); err != nil {
- return nil, err
- }
- s := &Statistics{}
- if res.Cpu != nil {
- s.CPU.Total = res.Cpu.GetTotal()
- s.CPU.Rate1M = res.Cpu.GetRate1M()
- s.CPU.Rate10M = res.Cpu.GetRate10M()
- }
- if res.Memory != nil {
- s.RAM.Current = res.Memory.GetCurrent()
- s.RAM.Average1M = res.Memory.GetAverage1M()
- s.RAM.Average10M = res.Memory.GetAverage10M()
- }
- return s, nil
- }
- /*
- RunInBackground makes an API call that triggers an /_ah/background request.
- There are two independent code paths that need to make contact:
- the RunInBackground code, and the /_ah/background handler. The matchmaker
- loop arranges for the two paths to meet. The RunInBackground code passes
- a send to the matchmaker, the /_ah/background passes a recv to the matchmaker,
- and the matchmaker hooks them up.
- */
- func init() {
- http.HandleFunc("/_ah/background", handleBackground)
- sc := make(chan send)
- rc := make(chan recv)
- sendc, recvc = sc, rc
- go matchmaker(sc, rc)
- }
- var (
- sendc chan<- send // RunInBackground sends to this
- recvc chan<- recv // handleBackground sends to this
- )
- type send struct {
- id string
- f func(context.Context)
- }
- type recv struct {
- id string
- ch chan<- func(context.Context)
- }
- func matchmaker(sendc <-chan send, recvc <-chan recv) {
- // When one side of the match arrives before the other
- // it is inserted in the corresponding map.
- waitSend := make(map[string]send)
- waitRecv := make(map[string]recv)
- for {
- select {
- case s := <-sendc:
- if r, ok := waitRecv[s.id]; ok {
- // meet!
- delete(waitRecv, s.id)
- r.ch <- s.f
- } else {
- // waiting for r
- waitSend[s.id] = s
- }
- case r := <-recvc:
- if s, ok := waitSend[r.id]; ok {
- // meet!
- delete(waitSend, r.id)
- r.ch <- s.f
- } else {
- // waiting for s
- waitRecv[r.id] = r
- }
- }
- }
- }
- var newContext = appengine.NewContext // for testing
- func handleBackground(w http.ResponseWriter, req *http.Request) {
- id := req.Header.Get("X-AppEngine-BackgroundRequest")
- ch := make(chan func(context.Context))
- recvc <- recv{id, ch}
- (<-ch)(newContext(req))
- }
- // RunInBackground runs f in a background goroutine in this process.
- // f is provided a context that may outlast the context provided to RunInBackground.
- // This is only valid to invoke from a manually scaled module.
- func RunInBackground(c context.Context, f func(c context.Context)) error {
- req := &pb.StartBackgroundRequestRequest{}
- res := &pb.StartBackgroundRequestResponse{}
- if err := internal.Call(c, "system", "StartBackgroundRequest", req, res); err != nil {
- return err
- }
- sendc <- send{res.GetRequestId(), f}
- return nil
- }
- func init() {
- internal.RegisterErrorCodeMap("system", pb.SystemServiceError_ErrorCode_name)
- }
|