Skip to content

Commit 4b6b194

Browse files
Merge pull request #196 from saltzm/main
Use Modal async Sandbox APIs
2 parents 9c2085b + 803db47 commit 4b6b194

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

src/swerex/deployment/modal.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,11 @@ async def is_alive(self, *, timeout: float | None = None) -> IsAliveResponse:
178178
"""
179179
if self._runtime is None or self._sandbox is None:
180180
raise DeploymentNotStartedError()
181-
if self._sandbox.poll() is not None:
181+
exit_code = await self._sandbox.poll.aio()
182+
if exit_code is not None:
182183
msg = "Container process terminated."
183-
output = "stdout:\n" + self._sandbox.stdout.read() # type: ignore
184-
output += "\nstderr:\n" + self._sandbox.stderr.read() # type: ignore
184+
output = "stdout:\n" + await self._sandbox.stdout.read.aio() # type: ignore
185+
output += "\nstderr:\n" + await self._sandbox.stderr.read.aio() # type: ignore
185186
msg += "\n" + output
186187
raise RuntimeError(msg)
187188
return await self._runtime.is_alive(timeout=timeout)
@@ -197,13 +198,13 @@ def _start_swerex_cmd(self, token: str) -> str:
197198
rex_args = f"--port {self._port} --auth-token {token}"
198199
return f"{REMOTE_EXECUTABLE_NAME} {rex_args} || pipx run {PACKAGE_NAME} {rex_args}"
199200

200-
def get_modal_log_url(self) -> str:
201+
async def get_modal_log_url(self) -> str:
201202
"""Returns URL to modal logs
202203
203204
Raises:
204205
DeploymentNotStartedError: If the deployment was not started.
205206
"""
206-
return f"https://modal.com/apps/{self._user}/main/deployed/{self.app.name}?activeTab=logs&taskId={self.sandbox._get_task_id()}"
207+
return f"https://modal.com/apps/{self._user}/main/deployed/{self.app.name}?activeTab=logs&taskId={await self.sandbox._get_task_id.aio()}"
207208

208209
async def start(
209210
self,
@@ -213,7 +214,7 @@ async def start(
213214
self._hooks.on_custom_step("Starting modal sandbox")
214215
t0 = time.time()
215216
token = self._get_token()
216-
self._sandbox = modal.Sandbox.create(
217+
self._sandbox = await modal.Sandbox.create.aio(
217218
"/usr/bin/env",
218219
"bash",
219220
"-c",
@@ -224,10 +225,11 @@ async def start(
224225
app=self._app,
225226
**self._modal_kwargs,
226227
)
227-
tunnel = self._sandbox.tunnels()[self._port]
228+
tunnels = await self._sandbox.tunnels.aio()
229+
tunnel = tunnels[self._port]
228230
elapsed_sandbox_creation = time.time() - t0
229231
self.logger.info(f"Sandbox ({self._sandbox.object_id}) created in {elapsed_sandbox_creation:.2f}s")
230-
self.logger.info(f"Check sandbox logs at {self.get_modal_log_url()}")
232+
self.logger.info(f"Check sandbox logs at {await self.get_modal_log_url()}")
231233
self.logger.info(f"Sandbox created with id {self._sandbox.object_id}")
232234
await asyncio.sleep(1)
233235
self.logger.info(f"Starting runtime at {tunnel.url}")
@@ -245,8 +247,10 @@ async def stop(self):
245247
if self._runtime is not None:
246248
await self._runtime.close()
247249
self._runtime = None
248-
if self._sandbox is not None and not self._sandbox.poll():
249-
self._sandbox.terminate()
250+
if self._sandbox is not None:
251+
exit_code = await self._sandbox.poll.aio()
252+
if exit_code is not None:
253+
await self._sandbox.terminate.aio()
250254
self._sandbox = None
251255
self._app = None
252256

tests/test_modal_deployment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
async def test_modal_deployment_from_docker_with_swerex_installed():
1111
dockerfile = Path(__file__).parent / "swe_rex_test.Dockerfile"
1212
image = _ImageBuilder().from_file(dockerfile, build_context=Path(__file__).resolve().parent.parent)
13-
d = ModalDeployment(image=image, startup_timeout=60)
13+
d = ModalDeployment(image=image, startup_timeout=60 * 5)
1414
with pytest.raises(RuntimeError):
1515
await d.is_alive()
1616
await d.start()

0 commit comments

Comments
 (0)