Repository navigation
Consolidate logging for HTTP requests, especially in timeout logging - #634
Merged
Merged
Conversation
torcolvin
force-pushed
the
shell2http-timeouts
branch
2 times, most recently
from
October 7, 2026 00:32
1e13b56 to
314b882
Compare
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Edge Server and Couchbase Server calls omit timeout propagation, so scripts can still outlive client timeouts without returning diagnostics.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Consolidates sidecar and REST request logging while adding host-side script timeouts and better diagnostics.
Changes:
- Adds reusable shell2http timeout handling.
- Centralizes request-failure logging.
- Adds coverage for timeout, status, and malformed-response behavior.
| File | Description |
|---|---|
environment/aws/sgw_setup/shell2http/start.sh |
Wraps SGW endpoints with timeout handling. |
environment/aws/sgw_setup/shell2http/start-sgw.sh |
Isolates SGW from timeout signals. |
environment/aws/sgw_setup/setup_sgw.py |
Uses shared script uploader. |
environment/aws/server_setup/shell2http/start.sh |
Wraps CBS endpoints. |
environment/aws/server_setup/setup_server.py |
Uses shared script uploader. |
environment/aws/es_setup/shell2http/start.sh |
Wraps Edge Server endpoints. |
environment/aws/es_setup/setup_edge_servers.py |
Uses shared script uploader. |
environment/aws/common/shell2http/with-timeout.sh |
Implements host-side timeout enforcement. |
environment/aws/common/io.py |
Adds shared sidecar-script upload utility. |
environment/AGENTS.md |
Documents shared timeout infrastructure. |
client/tests/test_syncgateway_sgcollect.py |
Updates request test stub. |
client/tests/test_syncgateway_helpers.py |
Tests SGW failure logging. |
client/tests/test_shell2http.py |
Tests the new sidecar client. |
client/tests/test_sgw_cluster_manager.py |
Updates timeout typing. |
client/tests/test_replica_counts.py |
Mocks the new CBS sidecar client. |
client/tests/test_edge_server.py |
Tests Edge Server failure logging. |
client/tests/test_edge_server_manager.py |
Updates sidecar and readiness stubs. |
client/tests/test_cluster.py |
Mocks the new CBS sidecar client. |
client/tests/test_bucket_cleanup.py |
Mocks the new CBS sidecar client. |
client/src/cbltest/utils.py |
Clarifies sidecar-port usage. |
client/src/cbltest/shell2http.py |
Adds the shared logged sidecar client. |
client/src/cbltest/plugins/sgw_cluster_manager.py |
Migrates SGW sidecar operations. |
client/src/cbltest/httplog.py |
Adds centralized exception recording. |
client/src/cbltest/api/syncgateway.py |
Logs failed SGW requests. |
client/src/cbltest/api/edgeservermanager.py |
Migrates Edge Server sidecar operations. |
client/src/cbltest/api/edgeserver.py |
Logs failed Edge Server requests. |
client/src/cbltest/api/couchbaseserver.py |
Migrates CBS sidecar operations. |
client/AGENTS.md |
Documents the sidecar client. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
A client-side timeout on a sidecar call lost the script's output.
shell2http killed only the top bash process, and child processes kept
running. shell2http's own -timeout flag applies to every call, and it
answers 200 for a killed script.
Now every sidecar call has a total HTTP timeout. The client sends 95%
of it as ?timeout=, and with-timeout.sh runs the script under GNU
timeout (SIGTERM to the process group, then SIGKILL 1s later). The host
stops the script first, so its output comes back as a 500. A call
without a timeout uses aiohttp's default of 300s, so the host stops it
at 285s. Sync Gateway calls keep their old values.
- Add environment/aws/common/shell2http/with-timeout.sh. All three
start.sh files run every endpoint through it.
- Add upload_shell2http_scripts() to environment/aws/common/io.py, so
the Couchbase Server, Sync Gateway and Edge Server setups upload the
wrapper.
- Add Shell2HttpClient in cbltest/shell2http.py. EdgeServerManager,
SyncGatewayManager and CouchbaseServer use it.
- call() fails unless the status is 2xx and X-Shell2http-Exit-Code
is 0. shell2http answers 200 when a signal kills the script.
- call() returns the script's output, and it raises the error type
that the client was built with. Edge Server keeps
CblEdgeServerBadResponseError. Sync Gateway and Couchbase Server now
raise CblRemoteBadResponseError, not CblTestError.
- Sync Gateway and Edge Server REST requests that get no response now
write an _error file and log to testserver.log, then raise again.
The new _HttpLogWriter.record_failure() does this for the REST
clients and the sidecar client.
- Readiness polls (Sync Gateway wait_for_rest_api, Edge Server start)
pass log_failure=False. Their expected connection errors still get
an _error file, but not a testserver.log line.
- start-sgw.sh starts Sync Gateway with setsid, as start-edgeserver.sh
does, so a host-side timeout does not kill the new Sync Gateway.
Logging, before and after
Before this change, none of these cases wrote to testserver.log. ERROR
lines also go to the console, at every --cbl-log-level.
1. Edge Server sidecar call succeeds
Before: http_log _begin and _end, as "Edge Server host [<h>]".
testserver.log: nothing.
After: http_log _begin and _end, as "Edge Server sidecar [<h>]",
and _end adds "(exit code 0)". testserver.log: nothing.
2. Sync Gateway or Couchbase Server sidecar call succeeds
Before: nothing logged.
After: http_log _begin and _end. testserver.log: nothing.
3. Script exits non-zero
Before: Edge Server: http_log _end with 500. Sync Gateway and
Couchbase Server: nothing logged, output only in the
exception. testserver.log: nothing.
After: http_log _end with "500 (exit code 1)" and the output.
testserver.log: ERROR line with the output.
4. Script runs past its timeout
Before: no limit on the host. Sync Gateway's client gave up at 120s
with no output, and the script kept running. Nothing logged,
except an Edge Server http_log _begin.
After: http_log _end with "500 (exit code 124)" and the output.
testserver.log: ERROR line with the output.
5. Script killed by a signal
Before: 200, so the call passed. Edge Server: http_log _end with
200. Sync Gateway and Couchbase Server: nothing logged.
testserver.log: nothing.
After: the call fails. http_log _end with "200 (exit code -1)".
testserver.log: ERROR line with the output.
6. Path the sidecar does not serve
Before: Edge Server: http_log _end with 404. Sync Gateway and
Couchbase Server: nothing logged. testserver.log: nothing.
After: http_log _end with "404 (exit code None)".
testserver.log: ERROR line with the body.
7. Sidecar call gets no response (client timeout, connection error)
Before: Edge Server: http_log _begin only. Sync Gateway and
Couchbase Server: nothing logged. testserver.log: nothing.
After: http_log _begin and _error. testserver.log: the same line
as _error, which ends with the timeouts that applied.
8. Sync Gateway or Edge Server REST request gets no response
Before: http_log _begin only. testserver.log: nothing.
After: http_log _begin and _error. testserver.log: the same line,
except for readiness polls, which log nothing there.
9. Sync Gateway or Edge Server REST request gets a bad status
Unchanged: http_log _begin and _end. testserver.log: nothing.
Examples (host names changed):
Case 2, http_log:
Sync Gateway sidecar [10.0.0.1] -> GET /stop-sgw?timeout=57
Sync Gateway sidecar [10.0.0.1] <- GET /stop-sgw?timeout=57 200 (exit code 0)
Case 4, testserver.log (http_log _end has the same output):
[ERROR]: Sync Gateway sidecar [10.0.0.1]: GET /start-sgw?config=bootstrap&timeout=0.57 returned 500 (exit code 124):
Starting Sync Gateway with config: /home/ec2-user/config/bootstrap.json...
Waiting for Sync Gateway to start (PID: 27759)...
start-sgw.sh timed out after 0.57s
exec error: exit status 124
Case 5, testserver.log:
[ERROR]: Edge Server sidecar [10.0.0.2]: POST /start-edgeserver returned 200 (exit code -1):
before kill
exec error: signal: killed
Case 7, http_log _error and testserver.log:
[ERROR]: Sync Gateway sidecar [10.0.0.1] <- GET /stop-sgw?timeout=57 failed: GET http://10.0.0.1:20001/stop-sgw?timeout=57 timed out after 60.0s waiting for the response (total 60s, sock_connect 30s)
Case 8, http_log _error and testserver.log:
[ERROR]: Edge Server [10.0.0.2] <- GET / failed: Expecting value: line 1 column 1 (char 0)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
torcolvin
force-pushed
the
shell2http-timeouts
branch
from
October 7, 2026 01:14
314b882 to
81e6036
Compare
torcolvin
marked this pull request as ready for review
October 7, 2026 01:15
borrrden
approved these changes
Oct 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Inspiration
@vipbhardwaj noticed that calling cbcollect would result in a timeout. It is definitely possible for some calls to timeout if part of the system times out. This could include shell2http, CBS REST, Sync Gateway REST, etc. Most of the code enforces a client side timeout (300s), but if it times you, can not necessarily figure out what times out.
What
Modify shell2http setup to take a
timeoutargument so that it can return the output of the process before it is killed. I pass 95% of the http timeout to leave time for shell2http to fail. This would help debug possibly understand where the process hangs. This is implemented using standardtimeoutcommand.Modify all the shell2http scripts to support
with-timeout.shto get picked up for CBS, SG, Edge Server.Fail if status for shell2http calls is not 200. If there is a signal, it will return 200 status but set
X-Shell2http-Exit-Codeto a negative number. Make sure this exception will show the output from a command.Use
setsidinstart-sgw.shto avoid killing Sync Gateway if there's a request timeout, like edge server.Move the code about timeouts to be consistent across
testerserver.logand the http logs. When I look at code, I never look at either of these files but only look at pytest output. Centralize this logic across requests.Make sure to log requests, timeouts into the log file. See below for changed. In order to do this, I catch and reraise exceptions.
Logging, before and after
Before this change, none of these cases wrote to
testserver.log.ERRORlines also go to the console, at every--cbl-log-level.http_logbeforehttp_logaftertestserver.logbeforetestserver.logafter_beginand_end, asEdge Server host [<h>]_beginand_end, asEdge Server sidecar [<h>], with(exit code 0)_beginand_end_endwith500. Sync Gateway and Couchbase Server: nothing, output only in the exception_endwith500 (exit code 1)and the outputERRORline with the output_beginonly. Sync Gateway and Couchbase Server: nothing. No limit on the host_endwith500 (exit code 124)and the outputERRORline with the output_endwith200, and the call passed. Sync Gateway and Couchbase Server: nothing_endwith200 (exit code -1), and the call failsERRORline with the output_endwith404. Sync Gateway and Couchbase Server: nothing_endwith404 (exit code None)ERRORline with the body_beginonly. Sync Gateway and Couchbase Server: nothing_beginand_error_errorline, which ends with the timeouts that applied_beginonly_beginand_error_errorline, except for readiness polls, which log nothing_beginand_endExamples
Host names are changed. The "after" output comes from runs against AWS hosts, a local shell2http v1.17.0 binary, or the unit tests.
1. Edge Server sidecar call succeeds
2. Sync Gateway sidecar call succeeds
3. Script exits non-zero (
/start-cbs)4. Script runs past its timeout (
/start-sgwwith a 0.6s timeout)A script can ignore
SIGTERM. ThenSIGKILLfollows 1s later, and the exit code is137. GNUtimeoutreturns137for anySIGKILL, so the wrapper does not claim a timeout:5. Script killed by a signal (
/start-edgeserver)6. Path the sidecar does not serve
7. Sidecar call gets no response
8. REST request gets no response
9. REST request gets a bad status: unchanged.
Notes
start_backend.py. A host with the old sidecar ignores?timeout=, and only the client's limit applies.testserver.logand the console get the full script output of a failed sidecar call. In practice the output is small. The largest is a failed/start-edgeserver, which prints a fresh Edge Server log./start-cbsalready failed onmain. It waits for/pools/defaultwithout credentials, which always answers401. Nothing intests/callsCouchbaseServer.start_server(). This PR does not fix that.Testing
uv run ruff check .,uv run --group lint ty check,uvx pre-commit run --all-files: pass.uv run -- pytest --config client/tests/empty_config.json client/tests: 395 passed.client/tests/test_shell2http.pycovers success with and without a timeout, and a client-side timeout. It also covers a500, a200with exit code-1, a404and the error type.test_syncgateway_helpers.pyandtest_edge_server.pycover REST requests that get no response.SyncGatewayManager.restart_with_config()took 2.7s and logged noERRORlines.EdgeServerManager.start_server()logged none either./start-cbswith a 5s timeout returned a500(exit code124) after 4.79s. The script's output was in the exception and in oneERRORline./start-edgeserverwith a 0.9s timeout returned a500(exit code124) with the script's output./start-sgw?timeout=0.2returned a500. The Sync Gateway that the script started was still running 5s later and answered on port 4984, sosetsidworks.SIGTERM, and a script that kills itself.🤖 Generated with Claude Code