mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Default Daytona auto-stop to 120 minutes
Omitting autoStopInterval from the create-sandbox request inherits Daytona's server-side default of 15 idle minutes. Daytona counts inactivity from the last sandbox interaction, and LLM inference never touches the sandbox, so a single long inference call is enough for the sandbox to auto-stop mid-run: a workflow failed exactly this way, with the sandbox entering its stop transition 15 minutes after the last command while the agent was still thinking. Send an explicit 120-minute default when lifecycle.auto_stop is unset. That clears any realistic inference call while still reclaiming sandboxes leaked by a dead worker. An explicit auto_stop = "0s" still disables auto-stop entirely. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
03c3412e51
commit
0845c331cb
3 changed files with 40 additions and 2 deletions
|
|
@ -321,7 +321,7 @@ memory = "8GB"
|
|||
| `network.allow` | CIDRs for `cidr_allow_list`; entries are validated as CIDRs. |
|
||||
| `lifecycle.preserve` | Keep the created sandbox after the run finishes. |
|
||||
| `lifecycle.stop_on_terminal` | Stop the sandbox when the run reaches a terminal state. |
|
||||
| `lifecycle.auto_stop` | Daytona auto-stop duration, such as `"30m"`. |
|
||||
| `lifecycle.auto_stop` | Daytona auto-stop duration, such as `"30m"`. Defaults to `"120m"`; `"0s"` disables auto-stop. |
|
||||
| `labels` | Provider labels. Merge by key across layers. |
|
||||
| `env` | Environment variables passed to command and agent execution. Merge by key across layers. |
|
||||
|
||||
|
|
|
|||
|
|
@ -198,6 +198,10 @@ The `lifecycle.auto_stop` setting tells Daytona to stop the sandbox after a peri
|
|||
auto_stop = "30m"
|
||||
```
|
||||
|
||||
When `auto_stop` is unset, Fabro applies a default of 120 minutes so a sandbox leaked by an interrupted run is still reclaimed. Set `auto_stop = "0s"` to disable auto-stop and let the sandbox run indefinitely.
|
||||
|
||||
Daytona counts inactivity from the last sandbox interaction (a command, file operation, or other API call). Time an agent spends on LLM inference does not touch the sandbox, so intervals shorter than your longest inference call risk stopping the sandbox mid-run.
|
||||
|
||||
## Server defaults
|
||||
|
||||
When running via `fabro server start`, the server config at `~/.fabro/settings.toml` can set default Daytona settings for all runs. Run config TOML values override server defaults. Labels are **merged** — run config labels win on key collisions. The `network` setting uses simple override (run config replaces the server default entirely).
|
||||
|
|
|
|||
|
|
@ -68,6 +68,12 @@ const DAYTONA_START_TIMEOUT: Duration = Duration::from_mins(1);
|
|||
/// deletion, temporary stdin files) so a stalled REST call cannot block
|
||||
/// cancellation/timeout paths indefinitely.
|
||||
const DAYTONA_CLEANUP_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
/// Auto-stop applied when `lifecycle.auto_stop` is unset. Omitting the field
|
||||
/// would inherit Daytona's server-side default of 15 idle minutes, which is
|
||||
/// shorter than a single long inference call and stops the sandbox mid-run;
|
||||
/// 120 minutes clears any realistic call while still reclaiming sandboxes
|
||||
/// leaked by a dead worker. An explicit `0` disables auto-stop entirely.
|
||||
const DEFAULT_AUTO_STOP_INTERVAL_MINUTES: i32 = 120;
|
||||
|
||||
/// Permissions a Daytona API key needs for Fabro's snapshot and sandbox flow.
|
||||
pub const REQUIRED_DAYTONA_PERMISSIONS: &[Permissions] = &[
|
||||
|
|
@ -727,7 +733,10 @@ impl DaytonaSandbox {
|
|||
daytona_sdk::SandboxBaseParams {
|
||||
name: Some(name),
|
||||
env_vars: Some(clean_bash_env(None)),
|
||||
auto_stop_interval: self.config.auto_stop_interval,
|
||||
auto_stop_interval: self
|
||||
.config
|
||||
.auto_stop_interval
|
||||
.or(Some(DEFAULT_AUTO_STOP_INTERVAL_MINUTES)),
|
||||
labels: Some(managed_labels::merge_for_run(
|
||||
self.config.labels.as_ref(),
|
||||
self.run_id.as_ref(),
|
||||
|
|
@ -2950,6 +2959,10 @@ mod tests {
|
|||
|
||||
assert_eq!(params.ephemeral, Some(false));
|
||||
assert_eq!(params.auto_delete_interval, Some(-1));
|
||||
assert_eq!(
|
||||
params.auto_stop_interval,
|
||||
Some(DEFAULT_AUTO_STOP_INTERVAL_MINUTES)
|
||||
);
|
||||
assert_eq!(
|
||||
params.env_vars,
|
||||
Some(HashMap::from([(BASH_ENV_VAR.to_string(), String::new())]))
|
||||
|
|
@ -2963,6 +2976,27 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn base_params_passes_explicit_auto_stop_through() {
|
||||
for interval in [0, 45] {
|
||||
let sandbox = DaytonaSandbox::new(
|
||||
DaytonaConfig {
|
||||
auto_stop_interval: Some(interval),
|
||||
..DaytonaConfig::default()
|
||||
},
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some("dtn_test".to_string()),
|
||||
)
|
||||
.await
|
||||
.expect("sandbox config should be valid");
|
||||
|
||||
assert_eq!(sandbox.base_params().auto_stop_interval, Some(interval));
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn activate_skips_start_when_daytona_reports_started() {
|
||||
let server = MockServer::start_async().await;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue