Skip to content

Commit 90ee0e3

Browse files
committed
fix(mothership): keep a long code call's upload bindings for its whole lifetime
1 parent c2d0733 commit 90ee0e3

3 files changed

Lines changed: 15 additions & 5 deletions

File tree

‎apps/sim/lib/mothership/tools/sandbox-project-files.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from '@/lib/mothership/tools/sandbox-callback'
1818
import {
1919
recordSandboxResourceEffects,
20+
SANDBOX_SCOPE_STATE_TTL_SECONDS,
2021
type SandboxResourceScope,
2122
} from '@/lib/mothership/tools/sandbox-resources'
2223
import { chatSandboxSessionKey } from '@/lib/mothership/tools/sandbox-session-key'
@@ -66,10 +67,11 @@ export async function proxySandboxProjectFileRequest(
6667
uploadBinding: {
6768
async record(uploadId) {
6869
await redis().eval(
69-
"redis.call('SADD', KEYS[1], ARGV[1]); redis.call('EXPIRE', KEYS[1], 600); return 1",
70+
"redis.call('SADD', KEYS[1], ARGV[1]); redis.call('EXPIRE', KEYS[1], ARGV[2]); return 1",
7071
1,
7172
bindingKey,
72-
uploadId
73+
uploadId,
74+
SANDBOX_SCOPE_STATE_TTL_SECONDS
7375
)
7476
},
7577
async contains(uploadId) {

‎apps/sim/lib/mothership/tools/sandbox-resources.test.ts‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,10 @@ describe('sandbox resource ownership and publication', () => {
200200
it('keeps the callback scope live for a call that outlasts its expiry, and revokes it after', async () => {
201201
vi.useFakeTimers()
202202
try {
203-
const finish = Promise.withResolvers<void>()
203+
let release = () => {}
204+
const finished = new Promise<void>((resolve) => {
205+
release = resolve
206+
})
204207
let token = ''
205208
const call = withSandboxResourceScope(
206209
identity,
@@ -210,12 +213,12 @@ describe('sandbox resource ownership and publication', () => {
210213
token =
211214
(await sandboxResourceEndpoint('https://sim.test', args, 'secret')).split('/').at(-1) ??
212215
''
213-
await finish.promise
216+
await finished
214217
}
215218
)
216219
await vi.advanceTimersByTimeAsync(15 * 60_000)
217220
expect(await readSandboxResourceScope(token, 'secret')).not.toBeNull()
218-
finish.resolve()
221+
release()
219222
await vi.advanceTimersByTimeAsync(1_000)
220223
await call
221224
expect(await readSandboxResourceScope(token, 'secret')).toBeNull()

‎apps/sim/lib/mothership/tools/sandbox-resources.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ const logger = createLogger('MothershipSandboxResources')
1818
const CONTEXT_TTL_SECONDS = 600
1919
/** A running call renews its scope well inside the TTL; the TTL only bounds a crashed owner. */
2020
const CONTEXT_RENEW_MS = (CONTEXT_TTL_SECONDS * 1000) / 3
21+
/**
22+
* Outlives the longest code call (15 minutes plus its settle margin). State keyed by a scope token
23+
* is reachable only through that token's live context, so outliving the context widens nothing.
24+
*/
25+
export const SANDBOX_SCOPE_STATE_TTL_SECONDS = 20 * 60
2126
const POLL_MS = 200
2227
const scopeSchema = z
2328
.object({

0 commit comments

Comments
 (0)