Skip to content

Commit

Permalink
Add docs about persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
mlejva committed Dec 17, 2024
1 parent c64e30a commit 51d328f
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 78 deletions.
2 changes: 0 additions & 2 deletions apps/web/src/app/(docs)/docs/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,12 @@ 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/>

147 changes: 140 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,149 @@
# Sandbox persistence

We're working on a feature that will allow you to persist sandboxes between runs.
<Note>
Sandbox persistence is currently in beta:
1. You need to install the [beta version of the SDKs](#installing-the-beta-version-of-the-sdks)
1. Consider [some limitations](#limitations-while-in-beta).
1. The persistence is free for all users during the beta.
</Note>

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 sandbox persistence allows you to pause your sandbox and resume it later from the same state it was in when you paused it.

**Prerequisites**
- Famil
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.

## 1. Installing the beta version of the SDKs
To use the sandbox persistence, you need to install the beta version of the SDKs.

<CodeGroup>
```bash {{ language: 'js' }}
npm i e2b@beta
```

## Amazon S3
```bash {{ language: 'python' }}

## Google Cloud Storage
# Install the latest beta version of the SDK on PyPi
# https://pypi.org/project/e2b/#history
pip install e2b-code-interpreter==1.1.0.b17
```
</CodeGroup>

## Cloudflare R2

## 2. 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.

<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() // $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>


## 3. 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
15 changes: 11 additions & 4 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,17 +32,17 @@ 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" />,
}
]

export function Concepts() {
return <BoxGrid items={concepts} noBackground />
}
}
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
15 changes: 11 additions & 4 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 Expand Up @@ -479,4 +486,4 @@ export const sdkRefRoutes: VersionedNavGroup[] = (
group?.title && sdkRefNameMap[group.title]
? sdkRefNameMap[group.title]
: group.title,
}))
}))
59 changes: 7 additions & 52 deletions apps/web/src/components/Tag.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,19 @@
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}
</span>
)
}
}

0 comments on commit 51d328f

Please sign in to comment.