@@ -218,6 +218,63 @@ async def test_stop_proc_mesh(self) -> None:
218
218
# now we doing casting without accessing the wrapped type.
219
219
del actor
220
220
221
+ async def test_stop_proc_mesh_context_manager (self ) -> None :
222
+ spec = AllocSpec (AllocConstraints (), host = 2 , gpu = 4 )
223
+
224
+ # create 2x process-allocators (on their own bind addresses) to simulate 2 hosts
225
+ with remote_process_allocator () as host1 , remote_process_allocator () as host2 :
226
+ allocator = RemoteAllocator (
227
+ world_id = "test_remote_allocator" ,
228
+ initializer = StaticRemoteAllocInitializer (host1 , host2 ),
229
+ heartbeat_interval = _100_MILLISECONDS ,
230
+ )
231
+ alloc = await allocator .allocate (spec )
232
+ proc_mesh = await ProcMesh .from_alloc (alloc )
233
+ with self .assertRaises (ValueError , msg = "foo" ):
234
+ async with proc_mesh :
235
+ actor = await proc_mesh .spawn ("test_actor" , TestActor )
236
+ # Ensure that proc mesh is stopped when context manager exits.
237
+ raise ValueError ("foo" )
238
+
239
+ with self .assertRaises (
240
+ RuntimeError , msg = "`ProcMesh` has already been stopped"
241
+ ):
242
+ await proc_mesh .spawn ("test_actor" , TestActor )
243
+
244
+ # TODO(agallagher): It'd be nice to test that this just fails
245
+ # immediately, trying to access the wrapped actor mesh, but right
246
+ # now we doing casting without accessing the wrapped type.
247
+ del actor
248
+
249
+ async def test_stop_proc_mesh_context_manager_multiple_times (self ) -> None :
250
+ spec = AllocSpec (AllocConstraints (), host = 2 , gpu = 4 )
251
+
252
+ # create 2x process-allocators (on their own bind addresses) to simulate 2 hosts
253
+ with remote_process_allocator () as host1 , remote_process_allocator () as host2 :
254
+ allocator = RemoteAllocator (
255
+ world_id = "test_remote_allocator" ,
256
+ initializer = StaticRemoteAllocInitializer (host1 , host2 ),
257
+ heartbeat_interval = _100_MILLISECONDS ,
258
+ )
259
+ alloc = await allocator .allocate (spec )
260
+ proc_mesh = await ProcMesh .from_alloc (alloc )
261
+ # We can nest multiple context managers on the same mesh, the innermost
262
+ # one closes the mesh and it cannot be used after that.
263
+ async with proc_mesh :
264
+ async with proc_mesh :
265
+ actor = await proc_mesh .spawn ("test_actor" , TestActor )
266
+
267
+ with self .assertRaises (
268
+ RuntimeError , msg = "`ProcMesh` has already been stopped"
269
+ ):
270
+ await proc_mesh .spawn ("test_actor" , TestActor )
271
+ # Exiting a second time should not raise an error.
272
+
273
+ # TODO(agallagher): It'd be nice to test that this just fails
274
+ # immediately, trying to access the wrapped actor mesh, but right
275
+ # now we doing casting without accessing the wrapped type.
276
+ del actor
277
+
221
278
async def test_stacked_1d_meshes (self ) -> None :
222
279
# create two stacked actor meshes on the same host
223
280
# each actor mesh running on separate process-allocators
0 commit comments