Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pause and resume to SDKs #474

Open
wants to merge 67 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
eaccd6e
[MVP] Add pause and resume
ValentaTomas Nov 12, 2024
b0b74ea
Add timeout to resume request
ValentaTomas Nov 12, 2024
500e31d
Improve pause/resume SDK return types and clarify usage
ValentaTomas Nov 25, 2024
891a147
Add a route for persistence to sidebar in docs
mlejva Dec 8, 2024
e8b479a
Add docs page for persistence
mlejva Dec 8, 2024
d11b709
Add mention of the persistence on the home page of docs
mlejva Dec 8, 2024
950190d
Add notes on current limitations
mlejva Dec 9, 2024
1c7052c
Update docs
mlejva Dec 9, 2024
1c82910
gen new python sdk model for snapshots
0div Dec 10, 2024
8b5f3d0
add resume method
0div Dec 10, 2024
5322c1b
add model init
0div Dec 10, 2024
8297cb2
add pause and resume methods to async python sdk
0div Dec 10, 2024
4b4922f
Expose timeoutMs in resume
ValentaTomas Dec 10, 2024
76eb025
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 10, 2024
1e2b6ea
Merge the snapshots-docs branch
mlejva Dec 10, 2024
7fc76d6
Merge branch 'main' of https://github.com/e2b-dev/E2B into add-pause-…
0div Dec 11, 2024
2aeb66c
make each test pause and resume the sbx
0div Dec 13, 2024
d7df1ef
Add prerelease tags
ValentaTomas Dec 13, 2024
5053639
Temporarily disable prerelease tests
ValentaTomas Dec 13, 2024
3610a7c
Fix version; Add metadata
ValentaTomas Dec 13, 2024
568ff75
[skip ci] Release new versions
github-actions[bot] Dec 13, 2024
babdb11
Cleanup pause and resume in SDKs
ValentaTomas Dec 13, 2024
a9814e5
[skip ci] Release new versions
github-actions[bot] Dec 13, 2024
b0c4cf1
Cleanup
ValentaTomas Dec 13, 2024
a179bed
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 13, 2024
9f9a36b
[skip ci] Release new versions
github-actions[bot] Dec 13, 2024
0d0ccab
add basic snapshot testing to python-sdk
0div Dec 14, 2024
c0591c9
[skip ci] Release new versions
github-actions[bot] Dec 14, 2024
484a69d
Tweak default request timeout
ValentaTomas Dec 15, 2024
45282fc
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 15, 2024
ba88225
[skip ci] Release new versions
github-actions[bot] Dec 15, 2024
16dcf6d
Update test
ValentaTomas Dec 15, 2024
9c473b7
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 15, 2024
5e545e2
[skip ci] Release new versions
github-actions[bot] Dec 15, 2024
7156e40
Parametrize template in tests
ValentaTomas Dec 16, 2024
39aa3a3
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
36c1054
Enable passing connect opts to resume class method
ValentaTomas Dec 16, 2024
9f52f81
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 16, 2024
636d3a3
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
6d67e92
Allow passing access token to api by parameter
ValentaTomas Dec 16, 2024
c4da73d
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 16, 2024
b4520b8
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
fc3c18f
Revert "Allow passing access token to api by parameter"
ValentaTomas Dec 16, 2024
c38a836
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 16, 2024
12898d8
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
d0acaf5
Pass api key and domain in sync python resume
ValentaTomas Dec 16, 2024
d451e03
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
4437a77
add deeper snapshot tests around memory, disk and long running processes
0div Dec 16, 2024
7714e01
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
fd94afc
remove base_01 template name and add http server test
0div Dec 16, 2024
7bab1ab
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
0div Dec 16, 2024
b7c8d71
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
1d9bee9
fix snapshot http server test
0div Dec 16, 2024
661f9b7
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
0div Dec 16, 2024
db8d846
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
1358b11
eslint
0div Dec 16, 2024
20ce5ac
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
78dc519
Add notes to docs about sandbox's timeout and network behavior
mlejva Dec 16, 2024
d3dcf9a
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
mlejva Dec 16, 2024
2d56f00
[skip ci] Release new versions
github-actions[bot] Dec 16, 2024
a5d97cd
Change the preid to beta
ValentaTomas Dec 17, 2024
4d835dc
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 17, 2024
9f21cce
[skip ci] Release new versions
github-actions[bot] Dec 17, 2024
dc90abb
Change tag to beta
ValentaTomas Dec 17, 2024
39b810e
Merge branch 'add-pause-and-resume-to-sdk-e2b-1190' of https://github…
ValentaTomas Dec 17, 2024
4bf8c63
[skip ci] Release new versions
github-actions[bot] Dec 17, 2024
67dc422
add test for ongoing long process listing and connection; added some …
0div Dec 17, 2024
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
40 changes: 20 additions & 20 deletions .github/workflows/release_candidates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ jobs:
virtualenvs-in-project: true
installer-parallel: true

- name: Test Python SDK
if: ${{ contains( github.event.pull_request.labels.*.name, 'python-rc') }}
working-directory: packages/python-sdk
run: |
poetry install
poetry run pytest --verbose -x
env:
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
# - name: Test Python SDK
# if: ${{ contains( github.event.pull_request.labels.*.name, 'python-rc') }}
# working-directory: packages/python-sdk
# run: |
# poetry install
# poetry run pytest --verbose -x
# env:
# E2B_API_KEY: ${{ secrets.E2B_API_KEY }}

- name: Release Candidate
if: ${{ contains( github.event.pull_request.labels.*.name, 'python-rc') }}
Expand All @@ -76,21 +76,21 @@ jobs:
run: |
pnpm install --frozen-lockfile

- name: Test JS SDK
working-directory: packages/js-sdk
if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }}
run: |
npx playwright install --with-deps
pnpm run test
env:
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
# - name: Test JS SDK
# working-directory: packages/js-sdk
# if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }}
# run: |
# npx playwright install --with-deps
# pnpm run test
# env:
# E2B_API_KEY: ${{ secrets.E2B_API_KEY }}

- name: Release JS Candidate
working-directory: packages/js-sdk
if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }}
run: |
npm version prerelease --preid=${{ github.head_ref }}
npm publish --tag rc
npm version prerelease --preid="beta"
npm publish --tag beta
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Expand All @@ -103,8 +103,8 @@ jobs:
working-directory: packages/cli
if: ${{ contains( github.event.pull_request.labels.*.name, 'cli-rc') }}
run: |
npm version prerelease --preid=${{ github.head_ref }}
npm publish --tag rc
npm version prerelease --preid="beta"
npm publish --tag beta
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Expand Down
3 changes: 0 additions & 3 deletions apps/web/src/app/(docs)/docs/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,11 @@ Some of the typical use cases for E2B are AI data analysis or visualization, run
The E2B Sandbox is a small isolated VM the can be started very quickly (~150ms). You can think of it as a small computer for the AI model. You can run many sandboxes at once. Typically, you run separate sandbox for each LLM, user, or AI agent session in your app.
For example, if you were building an AI data analysis chatbot, you would start the sandbox for every user session.


## Quickstart
<Quickstart/>

## Code interpreting with AI
<CodeInterpreting/>


## Learn the core concepts
<Concepts/>

129 changes: 122 additions & 7 deletions apps/web/src/app/(docs)/docs/sandbox/persistence/page.mdx
Original file line number Diff line number Diff line change
@@ -1,16 +1,131 @@
# Sandbox persistence

We're working on a feature that will allow you to persist sandboxes between runs.
<Note>
Sandbox persistence is currently in beta with [some limitations](#limitations-while-in-beta).

In the meantime, you can mount cloud storage like Amazon's S3, Google Cloud Storage, or Cloudflare's R2 to the sandbox's filesystem.
The persistence is free for all users during the beta.
</Note>

**Prerequisites**
- Famil
The sandbox persistence allows you to pause your sandbox and resume it later from the same state it was in when you paused it.

This includes not only state of the sandbox's filesystem but also the sandbox's memory. This means all running processes, loaded variables, data, etc.

## Pausing sandbox
When you pause a sandbox, both the sandbox's filesystem and memory state will be saved. This includes all the files in the sandbox's filesystem and all the running processes, loaded variables, data, etc.

## Amazon S3
<CodeGroup>
```js
import { Sandbox } from 'e2b'
// or use Code Interpreter: https://github.com/e2b-dev/code-interpreter
// import { Sandbox } from '@e2b/code-interpreter'
//
// or use Desktop: https://github.com/e2b-dev/desktop
// import { Sandbox } from '@e2b/desktop'

## Google Cloud Storage
const sbx = await Sandbox.create()
console.log('Sandbox created', sbx.sandboxId)

## Cloudflare R2
// Pause the sandbox
// You can save the sandbox ID in your database
// to resume the sandbox later
const sandboxId = await sbx.pause() // $HighlightLine
console.log('Sandbox paused', sandboxId) // $HighlightLine
```
```python
from e2b import Sandbox
# or use Code Interpreter: https://github.com/e2b-dev/code-interpreter
# from e2b_code_interpreter import Sandbox
#
# or use Desktop: https://github.com/e2b-dev/desktop
# from e2b_desktop import Sandbox

sbx = Sandbox()
print('Sandbox created', sbx.sandbox_id)

# Pause the sandbox
# You can save the sandbox ID in your database
# to resume the sandbox later
sandbox_id = sbx.pause() # $HighlightLine
print('Sandbox paused', sandbox_id) # $HighlightLine
```
</CodeGroup>


## Resuming sandbox
When you resume a sandbox, it will be in the same state it was in when you paused it.
This means that all the files in the sandbox's filesystem will be restored and all the running processes, loaded variables, data, etc. will be restored.

<CodeGroup>
```js
import { Sandbox } from 'e2b'
// or use Code Interpreter: https://github.com/e2b-dev/code-interpreter
// import { Sandbox } from '@e2b/code-interpreter'
//
// or use Desktop: https://github.com/e2b-dev/desktop
// import { Sandbox } from '@e2b/desktop'

const sbx = await Sandbox.create()
console.log('Sandbox created', sbx.sandboxId)

// Pause the sandbox
// You can save the sandbox ID in your database
// to resume the sandbox later
const sandboxId = await sbx.pause()
console.log('Sandbox paused', sandboxId)

// Resume the sandbox from the same state
const sameSbx = await Sandbox.resume(sandboxId) // $HighlightLine
console.log('Sandbox resumed', sameSbx.sandboxId) // $HighlightLine
```
```python
from e2b import Sandbox
# or use Code Interpreter: https://github.com/e2b-dev/code-interpreter
# from e2b_code_interpreter import Sandbox
#
# or use Desktop: https://github.com/e2b-dev/desktop
# from e2b_desktop import Sandbox

sbx = Sandbox()
print('Sandbox created', sbx.sandbox_id)

# Pause the sandbox
# You can save the sandbox ID in your database
# to resume the sandbox later
sandbox_id = sbx.pause()
print('Sandbox paused', sandbox_id)

# Resume the sandbox from the same state
same_sbx = Sandbox.resume(sandbox_id) # $HighlightLine
print('Sandbox resumed', same_sbx.sandbox_id) # $HighlightLine
```
</CodeGroup>

## Sandbox's timeout
When you resume a sandbox, the sandbox's timeout is reset to the default timeout of an E2B sandbox - 5 minutes.


You can pass a custom timeout to the `Sandbox.resume()` method like this:

<CodeGroup>
```js
import { Sandbox } from 'e2b'

const sbx = await Sandbox.resume(sandboxId, { timeoutMs: 60 * 1000 }) // 60 seconds
```
```python
from e2b import Sandbox

sbx = Sandbox.resume(sandbox_id, timeout=60) # 60 seconds
```
</CodeGroup>

## Network
If you have a service (for example a server) running inside your sandbox and you pause the sandbox, the service won't be accessible from the outside and all the clients will be disconnected.
If you resume the sandbox, the service will be accessible again but you need to connect clients again.


## Limitations while in beta
- It takes about 4 seconds per 1 GB RAM to pause the sandbox
- It takes about 2 seconds to resume the sandbox
- Soon, this will get to the same speed as calling `Sandbox.create()`
- Sandbox can be paused up to 30 days
13 changes: 10 additions & 3 deletions apps/web/src/components/Concepts.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
FolderTree,
Terminal,
Hourglass
Hourglass,
RefreshCcw,
} from 'lucide-react'

import {
Expand All @@ -16,6 +17,12 @@ const concepts: BoxItem[] = [
description: 'Learn about how to start the sandbox, manage its lifecycle, and interact with it.',
icon: <Hourglass strokeWidth={1.5} className="h-6 w-6 transition-colors duration-300 fill-white/10 stroke-zinc-400 group-hover:fill-brand-300/10 group-hover:stroke-brand-400" />,
},
{
href: '/docs/sandbox/persistence',
title: 'Sandbox persistence',
description: 'Learn how to achieve data persistence by pausing and resuming sandboxes.',
icon: <RefreshCcw strokeWidth={1.5} className="h-6 w-6 transition-colors duration-300 fill-white/10 stroke-zinc-400 group-hover:fill-brand-300/10 group-hover:stroke-brand-400" />,
},
// {
// href: '/docs/code-execution',
// title: 'AI code execution',
Expand All @@ -25,13 +32,13 @@ const concepts: BoxItem[] = [
{
href: '/docs/filesystem',
title: 'Filesystem',
description: 'Each sandbox has its own isolated filesystem that you can use to create, read, write, and delete files.',
description: 'Sandbox has an isolated filesystem that you can use to create, read, write, and delete files.',
icon: <FolderTree strokeWidth={1.5} className="h-6 w-6 transition-colors duration-300 fill-white/10 stroke-zinc-400 group-hover:fill-brand-300/10 group-hover:stroke-brand-400" />,
},
{
href: '/docs/commands',
title: 'Commands',
description: 'You can run terminal commands inside the Sandbox. This allows you to start any process inside the Sandbox.',
description: 'Run terminal commands inside the Sandbox and start any process inside the Sandbox.',
icon: <Terminal strokeWidth={1.5} className="h-6 w-6 transition-colors duration-300 fill-white/10 stroke-zinc-400 group-hover:fill-brand-300/10 group-hover:stroke-brand-400" />,
}
]
Expand Down
13 changes: 4 additions & 9 deletions apps/web/src/components/Navigation/NavigationLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import { NavLink } from './routes'
export function NavigationLink({
className,
link,
tag,
}: {

className?: string
link: NavLink
tag?: string
}) {
const pathname = usePathname()
// Add this to get the hash
Expand Down Expand Up @@ -41,17 +39,14 @@ export function NavigationLink({
>
<div className="flex items-center justify-start gap-1">
{link.icon}
{tag ? (
{link.tag ? (
<div className="flex items-center gap-2">
<Tag
variant="small"
color="emerald"
>
{tag}
</Tag>
<span className={clsx('truncate', isActive ? 'text-white' : '')}>
{link.title}
</span>
<Tag>
{link.tag}
</Tag>
</div>
) : (
<span className={clsx('truncate', isActive ? 'text-white' : '')}>
Expand Down
13 changes: 10 additions & 3 deletions apps/web/src/components/Navigation/routes.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { Braces, CheckCircle, Home, MessagesSquare } from 'lucide-react'
import sdkRefRoutesJson from './sdkRefRoutes.json'

enum Tag {
New = 'New',
}

export interface NavLink {
title: string
href: string
tag?: Tag
icon?: React.ReactNode
}

Expand Down Expand Up @@ -270,6 +275,11 @@ export const docRoutes: NavGroup[] = [
title: 'Lifecycle',
href: '/docs/sandbox',
},
{
title: 'Persistence',
tag: Tag.New,
href: '/docs/sandbox/persistence',
},
{
title: 'Metadata',
href: '/docs/sandbox/metadata',
Expand All @@ -295,9 +305,6 @@ export const docRoutes: NavGroup[] = [
// href: '/docs/sandbox/request-timeouts',
// },
// {
// title: '* Persistence',
// href: '/docs/sandbox/persistence',
// },
],
},
{
Expand Down
57 changes: 6 additions & 51 deletions apps/web/src/components/Tag.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,16 @@
import clsx from 'clsx'

const variantStyles = {
small: '',
medium: 'rounded-lg px-1.5 ring-1 ring-inset',
}

const colorStyles = {
emerald: {
small: 'text-brand-500 dark:text-brand-400',
medium:
'ring-brand-300 dark:ring-brand-400/30 bg-brand-400/10 text-brand-500 dark:text-brand-400',
},
sky: {
small: 'text-sky-500',
medium:
'ring-sky-300 bg-sky-400/10 text-sky-500 dark:ring-sky-400/30 dark:bg-sky-400/10 dark:text-sky-400',
},
amber: {
small: 'text-amber-500',
medium:
'ring-amber-300 bg-amber-400/10 text-amber-500 dark:ring-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400',
},
rose: {
small: 'text-red-500 dark:text-rose-500',
medium:
'ring-rose-200 bg-rose-50 text-red-500 dark:ring-rose-500/20 dark:bg-rose-400/10 dark:text-rose-400',
},
zinc: {
small: 'text-zinc-400 dark:text-zinc-500',
medium:
'ring-zinc-200 bg-zinc-50 text-zinc-500 dark:ring-zinc-500/20 dark:bg-zinc-400/10 dark:text-zinc-400',
},
}

const valueColorMap = {
GET: 'emerald',
POST: 'sky',
PUT: 'amber',
DELETE: 'rose',
} as Record<string, keyof typeof colorStyles>
import React from 'react'

export function Tag({
children,
variant = 'medium',
color = valueColorMap[children] ?? 'emerald',
}: {
// eslint-disable-next-line @typescript-eslint/ban-types
children: keyof typeof valueColorMap & (string | {})
variant?: keyof typeof variantStyles
color?: keyof typeof colorStyles
children,
}: {
children: React.ReactNode
}) {
return (
<span
className={clsx(
'relative top-[1px] font-mono text-[0.625rem] font-semibold',
variantStyles[variant],
colorStyles[color][variant],
'relative top-[1.5px] font-mono text-[0.625rem] font-semibold',
'text-brand-400 bg-brand-1000 ring-1 ring-inset rounded-lg px-1.5 ring-brand-400/20',
)}
>
{children}
Expand Down
Loading