bundler: limit the total number of goroutines to HandlerLimit

The bundler creates a goroutine per bundle. Only HandlerLimit can
execute in parallel so when write rates are high and handling is
slow, there can be a buildup of goroutines that are competing to
determine if it is their turn to execute. This behavior is
exhibited by TestConcurrentHandlersMax which occasionally fails
to terminate and generates 250,000+ goroutines within 2 seconds
on a 6-core 3.7ghz linux desktop.

In this change, we limit the total number of goroutines to
HandlerLimit. We change the bundle type to be a linked list where
items are added to the tail and handled from the head. Once the
user-specified handler returns within the goroutine, we check
if another bundle is ready for handling. If a bundle is ready,
the existing goroutine handles it. Otherwise, the goroutine ends.
This allows the goroutine count to grow and shrink as necessary.

Since we avoid sending bundles to goroutines prematurely, we
increase our opportunity to fill bundles to their maximum item
count.

This change allows bundler tests to execute and pass when
GOMAXPROCS=1. Previously they would fail to terminate.

Fixes #367
Fixes #417

Change-Id: I73a236ffe49087aedebbbbb6bbc94e0a041e93c1
Reviewed-on: https://code-review.googlesource.com/c/google-api-go-client/+/47991
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jean de Klerk <deklerk@google.com>
2 files changed
tree: b97cb575e7cc4b8df4364634f98e844d5542d8bb
  1. abusiveexperiencereport/
  2. acceleratedmobilepageurl/
  3. accessapproval/
  4. accesscontextmanager/
  5. adexchangebuyer/
  6. adexchangebuyer2/
  7. adexchangeseller/
  8. adexperiencereport/
  9. admin/
  10. adsense/
  11. adsensehost/
  12. alertcenter/
  13. analytics/
  14. analyticsreporting/
  15. androiddeviceprovisioning/
  16. androidenterprise/
  17. androidmanagement/
  18. androidpublisher/
  19. apigee/
  20. appengine/
  21. appsactivity/
  22. appstate/
  23. bigquery/
  24. bigqueryconnection/
  25. bigquerydatatransfer/
  26. bigqueryreservation/
  27. bigtableadmin/
  28. binaryauthorization/
  29. blogger/
  30. books/
  31. calendar/
  32. chat/
  33. civicinfo/
  34. classroom/
  35. cloudasset/
  36. cloudbilling/
  37. cloudbuild/
  38. cloudcommerceprocurement/
  39. clouddebugger/
  40. clouderrorreporting/
  41. cloudfunctions/
  42. cloudidentity/
  43. cloudiot/
  44. cloudkms/
  45. cloudprivatecatalog/
  46. cloudprivatecatalogproducer/
  47. cloudprofiler/
  48. cloudresourcemanager/
  49. cloudscheduler/
  50. cloudsearch/
  51. cloudshell/
  52. cloudtasks/
  53. cloudtrace/
  54. commentanalyzer/
  55. composer/
  56. compute/
  57. consumersurveys/
  58. container/
  59. containeranalysis/
  60. content/
  61. customsearch/
  62. datacatalog/
  63. dataflow/
  64. datafusion/
  65. dataproc/
  66. datastore/
  67. deploymentmanager/
  68. dfareporting/
  69. dialogflow/
  70. digitalassetlinks/
  71. discovery/
  72. dlp/
  73. dns/
  74. docs/
  75. domainsrdap/
  76. doubleclickbidmanager/
  77. doubleclicksearch/
  78. drive/
  79. driveactivity/
  80. examples/
  81. factchecktools/
  82. fcm/
  83. file/
  84. firebase/
  85. firebasedynamiclinks/
  86. firebasehosting/
  87. firebaseremoteconfig/
  88. firebaserules/
  89. firestore/
  90. fitness/
  91. fusiontables/
  92. games/
  93. gamesconfiguration/
  94. gamesmanagement/
  95. genomics/
  96. gmail/
  97. google-api-go-generator/
  98. googleapi/
  99. groupsmigration/
  100. groupssettings/
  101. healthcare/
  102. homegraph/
  103. iam/
  104. iamcredentials/
  105. iap/
  106. identitytoolkit/
  107. indexing/
  108. integration-tests/
  109. internal/
  110. iterator/
  111. jobs/
  112. kgsearch/
  113. language/
  114. lib/
  115. libraryagent/
  116. licensing/
  117. lifesciences/
  118. logging/
  119. manufacturers/
  120. mirror/
  121. ml/
  122. monitoring/
  123. oauth2/
  124. option/
  125. oslogin/
  126. pagespeedonline/
  127. partners/
  128. people/
  129. playcustomapp/
  130. playmoviespartner/
  131. plus/
  132. plusdomains/
  133. policytroubleshooter/
  134. poly/
  135. proximitybeacon/
  136. pubsub/
  137. qpxexpress/
  138. recommender/
  139. redis/
  140. remotebuildexecution/
  141. replicapool/
  142. replicapoolupdater/
  143. reseller/
  144. run/
  145. runtimeconfig/
  146. safebrowsing/
  147. script/
  148. searchconsole/
  149. securitycenter/
  150. servicebroker/
  151. serviceconsumermanagement/
  152. servicecontrol/
  153. servicemanagement/
  154. servicenetworking/
  155. serviceusage/
  156. serviceuser/
  157. sheets/
  158. siteverification/
  159. slides/
  160. sourcerepo/
  161. spanner/
  162. spectrum/
  163. speech/
  164. sql/
  165. sqladmin/
  166. storage/
  167. storagetransfer/
  168. streetviewpublish/
  169. support/
  170. surveys/
  171. tagmanager/
  172. tasks/
  173. testing/
  174. texttospeech/
  175. toolresults/
  176. tpu/
  177. tracing/
  178. translate/
  179. transport/
  180. urlshortener/
  181. vault/
  182. verifiedaccess/
  183. videointelligence/
  184. vision/
  185. webfonts/
  186. webmasters/
  187. websecurityscanner/
  188. youtube/
  189. youtubeanalytics/
  190. youtubereporting/
  191. .gitignore
  192. .hgtags
  193. api-list.json
  194. AUTHORS
  195. CHANGES.md
  196. CONTRIBUTING.md
  197. CONTRIBUTORS
  198. doc.go
  199. GettingStarted.md
  200. go.mod
  201. go.sum
  202. LICENSE
  203. license_test.go
  204. NOTES
  205. README.md
  206. RELEASING.md
  207. TODO
  208. tools.go
README.md

Google APIs Client Library for Go

Getting Started

$ go get google.golang.org/api/tasks/v1
$ go get google.golang.org/api/moderator/v1
$ go get google.golang.org/api/urlshortener/v1
... etc ...

and using:

package main

import (
	"net/http"

	"google.golang.org/api/urlshortener/v1"
)

func main() {
	svc, err := urlshortener.New(http.DefaultClient)
	// ...
}

Status

GoDoc

These are auto-generated Go libraries from the Google Discovery Service's JSON description files of the available “new style” Google APIs.

Due to the auto-generated nature of this collection of libraries, complete APIs or specific versions can appear or go away without notice. As a result, you should always locally vendor any API(s) that your code relies upon.

These client libraries are officially supported by Google. However, the libraries are considered complete and are in maintenance mode. This means that we will address critical bugs and security issues but will not add any new features.

If you're working with Google Cloud Platform APIs such as Datastore or Pub/Sub, consider using the Cloud Client Libraries for Go instead. These are the new and idiomatic Go libraries targeted specifically at Google Cloud Platform Services.

The generator itself and the code it produces are beta. Some APIs are alpha/beta, and indicated as such in the import path (e.g., “google.golang.org/api/someapi/v1alpha”).

Application Default Credentials Example

Application Default Credentials provide a simplified way to obtain credentials for authenticating with Google APIs.

The Application Default Credentials authenticate as the application itself, which make them great for working with Google Cloud APIs like Storage or Datastore. They are the recommended form of authentication when building applications that run on Google Compute Engine or Google App Engine.

Default credentials are provided by the golang.org/x/oauth2/google package. To use them, add the following import:

import "golang.org/x/oauth2/google"

Some credentials types require you to specify scopes, and service entry points may not inject them. If you encounter this situation you may need to specify scopes as follows:

import (
        "context"
        "golang.org/x/oauth2/google"
        "google.golang.org/api/compute/v1"
)

func main() {
        // Use oauth2.NoContext if there isn't a good context to pass in.
        ctx := context.Background()

        client, err := google.DefaultClient(ctx, compute.ComputeScope)
        if err != nil {
                //...
        }
        computeService, err := compute.New(client)
        if err != nil {
                //...
        }
}

If you need a oauth2.TokenSource, use the DefaultTokenSource function:

ts, err := google.DefaultTokenSource(ctx, scope1, scope2, ...)
if err != nil {
        //...
}
client := oauth2.NewClient(ctx, ts)

See also: golang.org/x/oauth2/google package documentation.