sandbox: timeout runsc commands

The current mechanism for forcing a process to die ater a timeout is not
sufficient. This change fixes issues that were causing processes to run
forever on the sandbox.

- Gracefully terminate processes before we kill them inside of our
gVisor process. This helps capture valuable debug output for the user.

- Return a friendlier error when our run context times out on the

- Add a test that timeouts are handled gracefully.

- Reduce concurrent goroutines in our sandbox run handler by replacing
goroutine copy functions with a custom writer (limitedWriter) that
returns an error if too much output is returned, halting the program.

- Custom writers (limitedWriter, switchWriter) also fix timing errors
when calling Wait() too soon on a Command, before we have read all of
the data. It also fixes a different error from trying to read data after
a program has terminated.

- Remove goroutine from startContainer, and use a ticker + context
timeout for synchronization.

Updates golang/go#25224
Updates golang/go#38343

Change-Id: Ie9d65220e5c4f39272ea70b45c4b472bcd7069bb
Run-TryBot: Alexander Rakoczy <>
TryBot-Result: Gobot Gobot <>
Reviewed-by: Bryan C. Mills <>
5 files changed
tree: 7f25616f7c8488f95f3d409f1aa51b3a67db32be
  1. cmd/
  2. deploy/
  3. examples/
  4. internal/
  5. sandbox/
  6. static/
  7. .gitignore
  8. app.yaml
  10. cache.go
  11. client.go
  12. codereview.cfg
  15. Dockerfile
  16. edit.go
  17. edit.html
  18. enable-fake-time.patch
  19. fake_fs.lst
  20. fmt.go
  21. fmt_test.go
  22. go.mod
  23. go.sum
  25. logger.go
  26. main.go
  27. Makefile
  29. play.go
  30. play_test.go
  32. sandbox.go
  33. server.go
  34. server_test.go
  35. share.go
  36. store.go
  37. tests.go
  38. txtar.go
  39. txtar_test.go
  40. vet.go


This subrepository holds the source for the Go playground:


# build the image
docker build -t playground .


docker run --name=play --rm -p 8080:8080 golang/playground &
# run some Go code
cat /path/to/code.go | go run client.go | curl -s --upload-file - localhost:8080/compile


Deployment Triggers

Playground releases automatically triggered when new Go repository tags are pushed to GitHub, or when master is pushed on the playground repository.

For details, see deploy/go_trigger.json, deploy/playground_trigger.json, and deploy/deploy.json.

After making changes to trigger configuration, update configuration by running the following Make target:

make update-cloudbuild-trigger

Deploy via Cloud Build

The Cloud Build configuration will always build and deploy with the latest supported release of Go.

gcloud builds submit --config deploy/deploy.json .

Deploy via gcloud app deploy

Building the playground Docker container takes more than the default 10 minute time limit of cloud build, so increase its timeout first (note, app/cloud_build_timeout is a global configuration value):

gcloud config set app/cloud_build_timeout 1200  # 20 mins

Alternatively, to avoid Cloud Build and build locally:

make docker
docker tag golang/playground:latest
docker push
gcloud --project=golang-org app deploy app.yaml


gcloud --project=golang-org app deploy app.yaml


To submit changes to this repository, see