Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
9196f94
feat(benchmark): add pool benchmark with standalone mock server and p…
Pangjiping Aug 14, 2026
81c95ab
refactor(benchmark): build Kotlin SDK from source via Gradle composit…
Pangjiping Aug 14, 2026
95b5c60
feat(benchmark): support production pool profile knobs (acquireMinRem…
Pangjiping Aug 14, 2026
e45ffc0
chore(benchmark): execd ping latency to fixed 100ms in the default pr…
Pangjiping Aug 14, 2026
fb3f1e4
feat(benchmark): add client-side instrumentation and explicit success…
Pangjiping Aug 14, 2026
a989cf5
feat(benchmark): consolidate all metrics into one run directory
Pangjiping Aug 14, 2026
e2edb25
docs(benchmark): fix stale default-profile comment in quick start
Pangjiping Aug 14, 2026
3b849c6
fix(benchmark): steady-state await must cover the full configured dur…
Pangjiping Aug 14, 2026
c370bb7
feat(benchmark): add --shared-connection-pool flag for connection-reu…
Pangjiping Aug 14, 2026
726b1d8
feat(benchmark): shared connection pool size sweep (--shared-connecti…
Pangjiping Aug 14, 2026
d06fa15
docs(benchmark): document warmup connection-churn problem and shared …
Pangjiping Aug 14, 2026
95b4d93
docs: document connection reuse at high warmup concurrency in the cli…
Pangjiping Aug 14, 2026
a1d8684
feat(benchmark): enable the shared connection pool by default (auto-s…
Pangjiping Aug 14, 2026
aa4ba06
feat(benchmark): fixed 500-idle-slot shared pool by default
Pangjiping Aug 14, 2026
e28aaaf
feat(benchmark): steady-start-immediately flag for startup-under-load…
Pangjiping Aug 14, 2026
8c25c68
fix(benchmark): address review feedback on mock fidelity and scenario…
Pangjiping Aug 17, 2026
47b6dd4
fix(benchmark): second round of review feedback
Pangjiping Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions docs/guides/client-pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,50 @@ canonical reference; refer to the per-language builder or constructor for exact
old-template sandbox IDs into the shared buffer during a rolling deploy.
- `resize(max_idle)` and `release_all_idle()` can be called from any node.

### Connection reuse at high warmup concurrency

**Problem.** Pool-created sandboxes go through the SDK transport per sandbox, and by
default each sandbox's HTTP client opens its own TCP connections — a warmup create
typically uses 2-4 fresh connections (create + endpoint lookups + readiness probe +
renew). At high `warmup_concurrency` the resulting connection burst can exceed what the
server listener can absorb (for example macOS accept backlog 128), producing intermittent
TCP-level `Connection reset` / `Broken pipe` failures. Failed warmups are retried
(backoff-gated), amplifying attempts several-fold and making fills slower and burstier
than at lower concurrency — measured in the Kotlin SDK benchmark harness at
`warmup_concurrency=1000`: ~80% of warmup attempts failed with 5x attempt amplification.

**Fix: share one transport connection pool.** Warmup creates then reuse connections
instead of opening new ones. Measured fill of 2000 idles at `warmup_concurrency=1000`
(Kotlin SDK, mock server):

| shared pool size | fill time | create failures | attempt amplification |
|---|---|---|---|
| 0 (per-sandbox connections) | ~20 s | ~8000 | 5x |
| 100 | ~9 s | ~2700 | 2.3x |
| 200 | ~7 s | ~1300 | 1.7x |
| 500 | ~4 s | 0 | 1x |

**Kotlin/Java.** Inject a shared `okhttp3.ConnectionPool` through the standard
`ConnectionConfig` — no pool-specific option is needed:

```kotlin
ConnectionConfig.builder()
.connectionPool(ConnectionPool(500, 5, TimeUnit.MINUTES)) // ~= warmup_concurrency
.build()
```

The pool uses this config for every sandbox it creates (warmup, direct create, idle
connect). A user-provided pool is treated as user-managed and is never evicted by the
SDK. A pool-created shared pool sized by `warmup_concurrency` will become the SDK
default once the companion change lands; until then configure it explicitly.

**Rule of thumb.** `warmup_concurrency` beyond ~200-300 only pays off together with a
shared connection pool — without reuse the extra threads mostly produce
connection-reset retries. If connections cannot be shared, keep
`warmup_concurrency` in the 200-300 range. The same principle applies to any SDK whose
transport opens connections per sandbox; see the language-local transport docs for how
to share a connection pool.

## Minimal usage

### Python (sync)
Expand Down
2 changes: 2 additions & 0 deletions tests/benchmark/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin/
results/
334 changes: 334 additions & 0 deletions tests/benchmark/README.md

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions tests/benchmark/configs/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"createLatencyMs": {
"distribution": "uniform",
"minMs": 300,
"maxMs": 800
},
"createFailureRate": 0.0,
"bootDelayMs": 300,
"execdFailureRate": 0.0,
"defaultTtlSeconds": 3600,
"latencyOverrides": {
"lifecycle.delete": {
"distribution": "uniform",
"minMs": 300,
"maxMs": 800
},
"lifecycle.get": {
"distribution": "uniform",
"minMs": 50,
"maxMs": 100
},
"lifecycle.renew": {
"distribution": "uniform",
"minMs": 50,
"maxMs": 100
},
"lifecycle.endpoint": {
"distribution": "uniform",
"minMs": 50,
"maxMs": 100
},
"execd.ping": {
"distribution": "fixed",
"meanMs": 100
},
"execd.other": {
"distribution": "uniform",
"minMs": 50,
"maxMs": 100
}
}
}
11 changes: 11 additions & 0 deletions tests/benchmark/configs/fast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"createLatencyMs": {
"distribution": "fixed",
"meanMs": 100
},
"createFailureRate": 0.0,
"bootDelayMs": 50,
"execdFailureRate": 0.0,
"defaultTtlSeconds": 3600,
"latencyOverrides": {}
}
13 changes: 13 additions & 0 deletions tests/benchmark/configs/slow.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"createLatencyMs": {
"distribution": "lognormal",
"meanMs": 2000,
"stddevMs": 1000,
"minMs": 100
},
"createFailureRate": 0.0,
"bootDelayMs": 1000,
"execdFailureRate": 0.0,
"defaultTtlSeconds": 3600,
"latencyOverrides": {}
}
58 changes: 58 additions & 0 deletions tests/benchmark/kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2026 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

plugins {
kotlin("jvm") version "2.2.21"
application
}

group = "com.alibaba.opensandbox"
version = "1.0.0"

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

repositories {
mavenCentral()
}

dependencies {
// OpenSandbox Kotlin SDK, built from source via composite build
// (see settings.gradle.kts). The module coordinate is substituted by the
// included build's :sandbox project; the version is informational only.
implementation("com.alibaba.opensandbox:sandbox:1.0.18")

implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
implementation("org.slf4j:slf4j-simple:2.0.9")
}

application {
mainClass.set("com.alibaba.opensandbox.benchmark.MainKt")
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
}
}

tasks.withType<JavaCompile> {
sourceCompatibility = "11"
targetCompatibility = "11"
}
4 changes: 4 additions & 0 deletions tests/benchmark/kotlin/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading
Loading