Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 sdks/sandbox/kotlin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,50 @@ sandboxes.getSandboxInfos().forEach(info -> {
// manager.close();
```

### 6. Sandbox Pool (Client-Side)

Use `SandboxPool` to keep an idle buffer of ready sandboxes and reduce acquire latency.

> ⚠ Experimental: `SandboxPool` is still evolving based on production feedback and may introduce breaking changes in future releases.

```java
import com.alibaba.opensandbox.sandbox.pool.SandboxPool;
import com.alibaba.opensandbox.sandbox.domain.pool.PoolCreationSpec;
import com.alibaba.opensandbox.sandbox.domain.pool.AcquirePolicy;
import com.alibaba.opensandbox.sandbox.infrastructure.pool.InMemoryPoolStateStore;

SandboxPool pool = SandboxPool.builder()
.poolName("demo-pool")
.ownerId("worker-1")
.maxIdle(3)
.stateStore(new InMemoryPoolStateStore()) // single-node store
.connectionConfig(config)
.creationSpec(
PoolCreationSpec.builder()
.image("ubuntu:22.04")
.entrypoint(java.util.List.of("tail", "-f", "/dev/null"))
.build()
)
.build();

pool.start();
Sandbox sb = pool.acquire(Duration.ofMinutes(10), AcquirePolicy.FAIL_FAST);
try {
sb.commands().run("echo pool-ok");
} finally {
sb.kill();
sb.close();
}
pool.shutdown(true);
```

Pool lifecycle semantics:
- `acquire()` is only allowed when pool state is `RUNNING`.
- In `DRAINING` / `STOPPED`, `acquire()` throws `PoolNotRunningException`.


> For distributed deployment, your application must provide a `PoolStateStore` implementation and ensure it satisfies distributed semantics (atomic idle take, idempotent put/remove, lock ownership/renewal, pool isolation, and consistent counters).

## Configuration

### 1. Connection Configuration
Expand Down
44 changes: 44 additions & 0 deletions sdks/sandbox/kotlin/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,50 @@ sandboxes.getSandboxInfos().forEach(info -> {
// manager.close();
```

### 6. Sandbox Pool(客户端池化)

你可以使用 `SandboxPool` 维护就绪沙箱的空闲缓冲区,以降低 `acquire` 延迟。

> ⚠ 实验性能力:`SandboxPool` 仍在根据真实生产场景持续演进,后续版本可能存在 breaking changes。

```java
import com.alibaba.opensandbox.sandbox.pool.SandboxPool;
import com.alibaba.opensandbox.sandbox.domain.pool.PoolCreationSpec;
import com.alibaba.opensandbox.sandbox.domain.pool.AcquirePolicy;
import com.alibaba.opensandbox.sandbox.infrastructure.pool.InMemoryPoolStateStore;

SandboxPool pool = SandboxPool.builder()
.poolName("demo-pool")
.ownerId("worker-1")
.maxIdle(3)
.stateStore(new InMemoryPoolStateStore()) // 单机实现
.connectionConfig(config)
.creationSpec(
PoolCreationSpec.builder()
.image("ubuntu:22.04")
.entrypoint(java.util.List.of("tail", "-f", "/dev/null"))
.build()
)
.build();

pool.start();
Sandbox sb = pool.acquire(Duration.ofMinutes(10), AcquirePolicy.FAIL_FAST);
try {
sb.commands().run("echo pool-ok");
} finally {
sb.kill();
sb.close();
}
pool.shutdown(true);
```

池状态语义:
- `acquire()` 仅允许在 `RUNNING` 状态调用。
- 在 `DRAINING` / `STOPPED` 状态,`acquire()` 会抛出 `PoolNotRunningException`。


> 在分布式部署场景下,需要由业务方自行提供 `PoolStateStore` 实现,并保证其满足分布式语义:原子 `tryTakeIdle`、`put/remove` 幂等、主锁所有权与续约、不同 `poolName` 隔离、以及计数一致性。

## 配置说明

### 1. 连接配置 (Connection Configuration)
Expand Down
228 changes: 0 additions & 228 deletions sdks/sandbox/kotlin/sandbox/Module.md

This file was deleted.

9 changes: 0 additions & 9 deletions sdks/sandbox/kotlin/sandbox/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,3 @@ tasks.withType<JavaCompile> {
)
}
}

tasks.withType<org.jetbrains.dokka.gradle.DokkaTask>().configureEach {
dokkaSourceSets {
named("main") {
moduleName.set("Sandbox")
includes.from("Module.md")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ class ConnectionConfig private constructor(
*/
val useServerProxy: Boolean = false,
) {
/**
* Creates a copy of this ConnectionConfig without copying the connectionPool.
* The returned config will have connectionPool set to null and connectionPoolManagedByUser set to false.
*/
fun copyWithoutConnectionPool(): ConnectionConfig =
ConnectionConfig(
apiKey = this.apiKey,
domain = this.domain,
protocol = this.protocol,
requestTimeout = this.requestTimeout,
debug = this.debug,
userAgent = this.userAgent,
headers = this.headers,
connectionPool = null,
connectionPoolManagedByUser = false,
useServerProxy = this.useServerProxy,
)

companion object {
private const val DEFAULT_DOMAIN = "localhost:8080"
private const val DEFAULT_PROTOCOL = "http"
Expand Down
Loading