runtime.go 3.9 KB

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