langfun 0.1.2.dev202509290805__py3-none-any.whl → 0.1.2.dev202510010805__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of langfun might be problematic. Click here for more details.

langfun/env/base_test.py CHANGED
@@ -280,7 +280,11 @@ class EnvironmentTests(unittest.TestCase):
280
280
  with self.assertRaises(interface.SandboxStateError):
281
281
  sb.shell('bad command', raise_error=interface.SandboxStateError)
282
282
  self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
283
- env.wait_for_housekeeping()
283
+ sb_offline_time = time.time()
284
+ while time.time() - sb_offline_time < 10:
285
+ if not env.is_online:
286
+ break
287
+ time.sleep(0.5)
284
288
  self.assertFalse(env.is_online)
285
289
 
286
290
 
@@ -381,34 +385,34 @@ class SandboxStatusTests(unittest.TestCase):
381
385
  self.assertEqual(
382
386
  self.event_handler.logs,
383
387
  [
384
- '[testing-env/0] shell: "feature1" setup',
385
- '[testing-env/0/feature1] feature setup',
386
- '[testing-env/0] shell: "feature2" setup',
387
- '[testing-env/0/feature2] feature setup',
388
- '[testing-env/0] shell: "feature1" setup session',
389
- '[testing-env/0/feature1] feature setup session',
390
- '[testing-env/0] shell: "feature2" setup session',
391
- '[testing-env/0/feature2] feature setup session',
392
- '[testing-env/0] created -> ready',
393
- '[testing-env/0] sandbox started',
388
+ '[testing-env/0:0] shell: "feature1" setup',
389
+ '[testing-env/0:0/feature1] feature setup',
390
+ '[testing-env/0:0] shell: "feature2" setup',
391
+ '[testing-env/0:0/feature2] feature setup',
392
+ '[testing-env/0:0] shell: "feature1" setup session',
393
+ '[testing-env/0:0/feature1] feature setup session',
394
+ '[testing-env/0:0] shell: "feature2" setup session',
395
+ '[testing-env/0:0/feature2] feature setup session',
396
+ '[testing-env/0:0] created -> ready',
397
+ '[testing-env/0:0] sandbox started',
394
398
  '[testing-env] environment started',
395
- '[testing-env/0] ready -> acquired',
396
- '[testing-env/0] acquired -> setting_up',
397
- '[testing-env/0] setting_up -> in_session',
398
- "[testing-env/0] session 'session1' started",
399
- '[testing-env/0/session1] shell: echo "hello"',
400
- '[testing-env/0] in_session -> exiting_session',
401
- '[testing-env/0/session1] shell: "feature1" teardown session',
402
- '[testing-env/0/feature1] feature teardown session',
403
- '[testing-env/0/session1] shell: "feature2" teardown session',
404
- '[testing-env/0/feature2] feature teardown session',
405
- "[testing-env/0] session 'session1' ended",
406
- '[testing-env/0] exiting_session -> setting_up',
407
- '[testing-env/0] shell: "feature1" setup session',
408
- '[testing-env/0/feature1] feature setup session',
409
- '[testing-env/0] shell: "feature2" setup session',
410
- '[testing-env/0/feature2] feature setup session',
411
- '[testing-env/0] setting_up -> ready'
399
+ '[testing-env/0:0] ready -> acquired',
400
+ '[testing-env/0:0] acquired -> setting_up',
401
+ '[testing-env/0:0] setting_up -> in_session',
402
+ "[testing-env/0:0] session 'session1' started",
403
+ '[testing-env/0:0/session1] shell: echo "hello"',
404
+ '[testing-env/0:0] in_session -> exiting_session',
405
+ '[testing-env/0:0/session1] shell: "feature1" teardown session',
406
+ '[testing-env/0:0/feature1] feature teardown session',
407
+ '[testing-env/0:0/session1] shell: "feature2" teardown session',
408
+ '[testing-env/0:0/feature2] feature teardown session',
409
+ "[testing-env/0:0] session 'session1' ended",
410
+ '[testing-env/0:0] exiting_session -> setting_up',
411
+ '[testing-env/0:0] shell: "feature1" setup session',
412
+ '[testing-env/0:0/feature1] feature setup session',
413
+ '[testing-env/0:0] shell: "feature2" setup session',
414
+ '[testing-env/0:0/feature2] feature setup session',
415
+ '[testing-env/0:0] setting_up -> ready'
412
416
  ]
413
417
  )
414
418
 
@@ -440,17 +444,19 @@ class SandboxStatusTests(unittest.TestCase):
440
444
  self.assertEqual(
441
445
  event_handler.logs,
442
446
  [
443
- '[testing-env/0] in_session -> exiting_session',
444
- '[testing-env/0/session1] shell: "test_feature" teardown session',
445
- '[testing-env/0/test_feature] feature teardown session',
446
- "[testing-env/0] session 'session1' ended",
447
- '[testing-env/0] exiting_session -> setting_up',
448
- '[testing-env/0/test_feature] feature setup session with SandboxStateError', # pylint: disable=line-too-long
449
- '[testing-env/0] setting_up -> shutting_down',
450
- '[testing-env/0] shell: "test_feature" teardown',
451
- '[testing-env/0/test_feature] feature teardown',
452
- '[testing-env/0] shutting_down -> offline',
453
- '[testing-env/0] sandbox shutdown'
447
+ # pylint: disable=line-too-long
448
+ '[testing-env/0:0] in_session -> exiting_session',
449
+ '[testing-env/0:0/session1] shell: "test_feature" teardown session',
450
+ '[testing-env/0:0/test_feature] feature teardown session',
451
+ "[testing-env/0:0] session 'session1' ended",
452
+ '[testing-env/0:0] exiting_session -> setting_up',
453
+ '[testing-env/0:0/test_feature] feature setup session with SandboxStateError', # pylint: disable=line-too-long
454
+ '[testing-env/0:0] setting_up -> shutting_down',
455
+ '[testing-env/0:0] shell: "test_feature" teardown',
456
+ '[testing-env/0:0/test_feature] feature teardown',
457
+ '[testing-env/0:0] shutting_down -> offline',
458
+ '[testing-env/0:0] sandbox shutdown'
459
+ # pylint: enable=line-too-long
454
460
  ]
455
461
  )
456
462
 
@@ -493,10 +499,10 @@ class SandboxStatusTests(unittest.TestCase):
493
499
  self.assertEqual(
494
500
  self.event_handler.logs,
495
501
  [
496
- '[testing-env/0] sandbox started with SandboxStateError',
497
- '[testing-env/0] created -> shutting_down',
498
- '[testing-env/0] shutting_down -> offline',
499
- '[testing-env/0] sandbox shutdown',
502
+ '[testing-env/0:0] sandbox started with SandboxStateError',
503
+ '[testing-env/0:0] created -> shutting_down',
504
+ '[testing-env/0:0] shutting_down -> offline',
505
+ '[testing-env/0:0] sandbox shutdown',
500
506
  '[testing-env] environment started with EnvironmentOutageError',
501
507
  '[testing-env] environment shutdown'
502
508
  ]
@@ -569,24 +575,24 @@ class SandboxStatusTests(unittest.TestCase):
569
575
  self.assertEqual(
570
576
  self.event_handler.logs,
571
577
  [
572
- '[testing-env/0] shell: "feature1" setup',
573
- '[testing-env/0/feature1] feature setup',
574
- '[testing-env/0] shell: "feature2" setup',
575
- '[testing-env/0/feature2] feature setup',
576
- '[testing-env/0] shell: "feature1" setup session',
577
- '[testing-env/0/feature1] feature setup session',
578
- '[testing-env/0] shell: "feature2" setup session',
579
- '[testing-env/0/feature2] feature setup session',
580
- '[testing-env/0] created -> ready',
581
- '[testing-env/0] sandbox started',
578
+ '[testing-env/0:0] shell: "feature1" setup',
579
+ '[testing-env/0:0/feature1] feature setup',
580
+ '[testing-env/0:0] shell: "feature2" setup',
581
+ '[testing-env/0:0/feature2] feature setup',
582
+ '[testing-env/0:0] shell: "feature1" setup session',
583
+ '[testing-env/0:0/feature1] feature setup session',
584
+ '[testing-env/0:0] shell: "feature2" setup session',
585
+ '[testing-env/0:0/feature2] feature setup session',
586
+ '[testing-env/0:0] created -> ready',
587
+ '[testing-env/0:0] sandbox started',
582
588
  '[testing-env] environment started',
583
- '[testing-env/0] ready -> shutting_down',
584
- '[testing-env/0] shell: "feature1" teardown',
585
- '[testing-env/0/feature1] feature teardown',
586
- '[testing-env/0] shell: "feature2" teardown',
587
- '[testing-env/0/feature2] feature teardown',
588
- '[testing-env/0] shutting_down -> offline',
589
- '[testing-env/0] sandbox shutdown with ValueError',
589
+ '[testing-env/0:0] ready -> shutting_down',
590
+ '[testing-env/0:0] shell: "feature1" teardown',
591
+ '[testing-env/0:0/feature1] feature teardown',
592
+ '[testing-env/0:0] shell: "feature2" teardown',
593
+ '[testing-env/0:0/feature2] feature teardown',
594
+ '[testing-env/0:0] shutting_down -> offline',
595
+ '[testing-env/0:0] sandbox shutdown with ValueError',
590
596
  '[testing-env] environment shutdown with ValueError'
591
597
  ]
592
598
  )
@@ -998,27 +1004,27 @@ class SandboxStatusTests(unittest.TestCase):
998
1004
  self.assertEqual(
999
1005
  self.event_handler.logs,
1000
1006
  [
1001
- '[testing-env/0] shell: "feature1" setup',
1002
- '[testing-env/0/feature1] feature setup',
1003
- '[testing-env/0] shell: "feature1" setup session',
1004
- '[testing-env/0/feature1] feature setup session',
1005
- '[testing-env/0] created -> ready',
1006
- '[testing-env/0] sandbox started',
1007
+ '[testing-env/0:0] shell: "feature1" setup',
1008
+ '[testing-env/0:0/feature1] feature setup',
1009
+ '[testing-env/0:0] shell: "feature1" setup session',
1010
+ '[testing-env/0:0/feature1] feature setup session',
1011
+ '[testing-env/0:0] created -> ready',
1012
+ '[testing-env/0:0] sandbox started',
1007
1013
  '[testing-env] environment started',
1008
- '[testing-env/0] ready -> acquired',
1009
- '[testing-env/0] acquired -> setting_up',
1010
- '[testing-env/0] setting_up -> in_session',
1011
- "[testing-env/0] session 'session1' started",
1012
- '[testing-env/0/session1] shell: echo foo with ValueError',
1013
- '[testing-env/0/session1] shell: echo bar',
1014
- '[testing-env/0] in_session -> exiting_session',
1015
- '[testing-env/0/session1] shell: "feature1" teardown session',
1016
- '[testing-env/0/feature1] feature teardown session',
1017
- "[testing-env/0] session 'session1' ended",
1018
- '[testing-env/0] exiting_session -> setting_up',
1019
- '[testing-env/0] shell: "feature1" setup session',
1020
- '[testing-env/0/feature1] feature setup session',
1021
- '[testing-env/0] setting_up -> ready',
1014
+ '[testing-env/0:0] ready -> acquired',
1015
+ '[testing-env/0:0] acquired -> setting_up',
1016
+ '[testing-env/0:0] setting_up -> in_session',
1017
+ "[testing-env/0:0] session 'session1' started",
1018
+ '[testing-env/0:0/session1] shell: echo foo with ValueError',
1019
+ '[testing-env/0:0/session1] shell: echo bar',
1020
+ '[testing-env/0:0] in_session -> exiting_session',
1021
+ '[testing-env/0:0/session1] shell: "feature1" teardown session',
1022
+ '[testing-env/0:0/feature1] feature teardown session',
1023
+ "[testing-env/0:0] session 'session1' ended",
1024
+ '[testing-env/0:0] exiting_session -> setting_up',
1025
+ '[testing-env/0:0] shell: "feature1" setup session',
1026
+ '[testing-env/0:0/feature1] feature setup session',
1027
+ '[testing-env/0:0] setting_up -> ready',
1022
1028
  ]
1023
1029
  )
1024
1030
 
@@ -1039,29 +1045,31 @@ class SandboxStatusTests(unittest.TestCase):
1039
1045
  self.assertEqual(
1040
1046
  self.event_handler.logs,
1041
1047
  [
1042
- '[testing-env/0] shell: "feature1" setup',
1043
- '[testing-env/0/feature1] feature setup',
1044
- '[testing-env/0] shell: "feature1" setup session',
1045
- '[testing-env/0/feature1] feature setup session',
1046
- '[testing-env/0] created -> ready',
1047
- '[testing-env/0] sandbox started',
1048
+ # pylint: disable=line-too-long
1049
+ '[testing-env/0:0] shell: "feature1" setup',
1050
+ '[testing-env/0:0/feature1] feature setup',
1051
+ '[testing-env/0:0] shell: "feature1" setup session',
1052
+ '[testing-env/0:0/feature1] feature setup session',
1053
+ '[testing-env/0:0] created -> ready',
1054
+ '[testing-env/0:0] sandbox started',
1048
1055
  '[testing-env] environment started',
1049
- '[testing-env/0] ready -> acquired',
1050
- '[testing-env/0] acquired -> setting_up',
1051
- '[testing-env/0] setting_up -> in_session',
1052
- "[testing-env/0] session 'session1' started",
1053
- '[testing-env/0/session1] shell: echo foo with RuntimeError',
1054
- '[testing-env/0] in_session -> exiting_session',
1055
- '[testing-env/0/session1] shell: "feature1" teardown session',
1056
- '[testing-env/0/feature1] feature teardown session',
1057
- "[testing-env/0] session 'session1' ended with SandboxStateError",
1058
- '[testing-env/0] exiting_session -> acquired',
1059
- '[testing-env/0] acquired -> shutting_down',
1060
- '[testing-env/0] shell: "feature1" teardown',
1061
- '[testing-env/0/feature1] feature teardown',
1062
- '[testing-env/0] shutting_down -> offline',
1063
- '[testing-env/0] sandbox shutdown',
1064
- '[testing-env/0] shell: echo bar',
1056
+ '[testing-env/0:0] ready -> acquired',
1057
+ '[testing-env/0:0] acquired -> setting_up',
1058
+ '[testing-env/0:0] setting_up -> in_session',
1059
+ "[testing-env/0:0] session 'session1' started",
1060
+ '[testing-env/0:0/session1] shell: echo foo with RuntimeError',
1061
+ '[testing-env/0:0] in_session -> exiting_session',
1062
+ '[testing-env/0:0/session1] shell: "feature1" teardown session',
1063
+ '[testing-env/0:0/feature1] feature teardown session',
1064
+ "[testing-env/0:0] session 'session1' ended with SandboxStateError",
1065
+ '[testing-env/0:0] exiting_session -> acquired',
1066
+ '[testing-env/0:0] acquired -> shutting_down',
1067
+ '[testing-env/0:0] shell: "feature1" teardown',
1068
+ '[testing-env/0:0/feature1] feature teardown',
1069
+ '[testing-env/0:0] shutting_down -> offline',
1070
+ '[testing-env/0:0] sandbox shutdown',
1071
+ '[testing-env/0:0] shell: echo bar',
1072
+ # pylint: enable=line-too-long
1065
1073
  ]
1066
1074
  )
1067
1075
 
@@ -1107,12 +1115,15 @@ class SandboxActivityTests(unittest.TestCase):
1107
1115
  self.assertEqual(sb.status, sb.Status.OFFLINE)
1108
1116
 
1109
1117
  def test_housekeep_error(self):
1118
+ event_handler = TestingEventHandler(log_housekeep=False)
1110
1119
  env = TestingEnvironment(
1111
1120
  features={'test_feature': TestingFeature(housekeep_interval=0)},
1112
1121
  pool_size=1,
1122
+ housekeep_interval=1.0,
1113
1123
  outage_grace_period=0,
1114
- outage_retry_interval=0,
1124
+ outage_retry_interval=0.1,
1115
1125
  sandbox_keepalive_interval=0,
1126
+ event_handlers=[event_handler],
1116
1127
  )
1117
1128
  with env:
1118
1129
  with env.sandbox('session1') as sb:
@@ -1129,6 +1140,31 @@ class SandboxActivityTests(unittest.TestCase):
1129
1140
  ):
1130
1141
  time.sleep(0.01)
1131
1142
  self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
1143
+ env.wait_for_housekeeping()
1144
+ self.assertEqual(
1145
+ event_handler.logs,
1146
+ [
1147
+ '[testing-env/0:0] shell: "test_feature" setup',
1148
+ '[testing-env/0:0/test_feature] feature setup',
1149
+ '[testing-env/0:0] shell: "test_feature" setup session',
1150
+ '[testing-env/0:0] sandbox started',
1151
+ '[testing-env] environment started',
1152
+ "[testing-env/0:0] session 'session1' started",
1153
+ '[testing-env/0:0/session1] shell: "test_feature" teardown session',
1154
+ "[testing-env/0:0] session 'session1' ended with SandboxStateError",
1155
+ '[testing-env/0:0] shell: "test_feature" teardown',
1156
+ '[testing-env/0:0/test_feature] feature teardown',
1157
+ '[testing-env/0:0] sandbox shutdown',
1158
+ '[testing-env/0:1] shell: "test_feature" setup',
1159
+ '[testing-env/0:1/test_feature] feature setup',
1160
+ '[testing-env/0:1] shell: "test_feature" setup session',
1161
+ '[testing-env/0:1] sandbox started',
1162
+ '[testing-env/0:1] shell: "test_feature" teardown',
1163
+ '[testing-env/0:1/test_feature] feature teardown',
1164
+ '[testing-env/0:1] sandbox shutdown',
1165
+ '[testing-env] environment shutdown'
1166
+ ]
1167
+ )
1132
1168
 
1133
1169
  def test_remove_event_handler(self):
1134
1170
  env = TestingEnvironment(
@@ -1145,6 +1181,7 @@ class SandboxActivityTests(unittest.TestCase):
1145
1181
  sb.shell('test_feature')
1146
1182
  sb.remove_event_handler(event_handler)
1147
1183
  events = list(event_handler.logs)
1184
+ sb.wait_until_not(interface.Sandbox.Status.SETTING_UP)
1148
1185
  self.assertGreater(len(events), 0)
1149
1186
  with env.sandbox('session2') as sb:
1150
1187
  sb.shell('test_feature')
@@ -8,5 +8,7 @@ from langfun.env.event_handlers.base import EventHandler
8
8
  from langfun.env.event_handlers.event_logger import EventLogger
9
9
  from langfun.env.event_handlers.event_logger import ConsoleEventLogger
10
10
 
11
+ from langfun.env.event_handlers.metric_writer import MetricWriter
12
+
11
13
  # pylint: enable=g-importing-member
12
14
  # pylint: enable=g-bad-import-order
@@ -48,6 +48,7 @@ class _SessionEventHandler:
48
48
  environment: Environment,
49
49
  sandbox: Sandbox,
50
50
  session_id: str,
51
+ duration: float,
51
52
  lifetime: float,
52
53
  error: BaseException | None
53
54
  ) -> None:
@@ -57,6 +58,7 @@ class _SessionEventHandler:
57
58
  environment: The environment.
58
59
  sandbox: The sandbox.
59
60
  session_id: The session ID.
61
+ duration: The time spent on ending the session.
60
62
  lifetime: The session lifetime in seconds.
61
63
  error: The error that caused the session to end. If None, the session
62
64
  ended normally.
@@ -74,7 +76,16 @@ class _FeatureEventHandler:
74
76
  duration: float,
75
77
  error: BaseException | None
76
78
  ) -> None:
77
- """Called when a sandbox feature is setup."""
79
+ """Called when a sandbox feature is setup.
80
+
81
+ Args:
82
+ environment: The environment.
83
+ sandbox: The sandbox.
84
+ feature: The feature.
85
+ duration: The feature setup duration in seconds.
86
+ error: The error happened during the feature setup. If None,
87
+ the feature setup performed normally.
88
+ """
78
89
 
79
90
  def on_feature_teardown(
80
91
  self,
@@ -84,7 +95,16 @@ class _FeatureEventHandler:
84
95
  duration: float,
85
96
  error: BaseException | None
86
97
  ) -> None:
87
- """Called when a sandbox feature is teardown."""
98
+ """Called when a sandbox feature is teardown.
99
+
100
+ Args:
101
+ environment: The environment.
102
+ sandbox: The sandbox.
103
+ feature: The feature.
104
+ duration: The feature teardown duration in seconds.
105
+ error: The error happened during the feature teardown. If None,
106
+ the feature teardown performed normally.
107
+ """
88
108
 
89
109
  def on_feature_teardown_session(
90
110
  self,
@@ -95,7 +115,17 @@ class _FeatureEventHandler:
95
115
  duration: float,
96
116
  error: BaseException | None
97
117
  ) -> None:
98
- """Called when a feature is teardown with a session."""
118
+ """Called when a feature is teardown with a session.
119
+
120
+ Args:
121
+ environment: The environment.
122
+ sandbox: The sandbox.
123
+ feature: The feature.
124
+ session_id: The session ID.
125
+ duration: The feature teardown session duration in seconds.
126
+ error: The error happened during the feature teardown session. If
127
+ None, the feature teardown session performed normally.
128
+ """
99
129
 
100
130
  def on_feature_setup_session(
101
131
  self,
@@ -104,9 +134,19 @@ class _FeatureEventHandler:
104
134
  feature: Feature,
105
135
  session_id: str | None,
106
136
  duration: float,
107
- error: BaseException | None
137
+ error: BaseException | None,
108
138
  ) -> None:
109
- """Called when a feature is setup with a session."""
139
+ """Called when a feature is setup with a session.
140
+
141
+ Args:
142
+ environment: The environment.
143
+ sandbox: The sandbox.
144
+ feature: The feature.
145
+ session_id: The session ID.
146
+ duration: The feature setup session duration in seconds.
147
+ error: The error happened during the feature setup session. If
148
+ None, the feature setup session performed normally.
149
+ """
110
150
 
111
151
  def on_feature_housekeep(
112
152
  self,
@@ -115,9 +155,21 @@ class _FeatureEventHandler:
115
155
  feature: Feature,
116
156
  counter: int,
117
157
  duration: float,
118
- error: BaseException | None
158
+ error: BaseException | None,
159
+ **kwargs,
119
160
  ) -> None:
120
- """Called when a sandbox feature is housekeeping."""
161
+ """Called when a sandbox feature is housekeeping.
162
+
163
+ Args:
164
+ environment: The environment.
165
+ sandbox: The sandbox.
166
+ feature: The feature.
167
+ counter: Zero-based counter of the housekeeping round.
168
+ duration: The feature housekeeping duration in seconds.
169
+ error: The error happened during the feature housekeeping. If None, the
170
+ feature housekeeping normally.
171
+ **kwargs: Feature-specific properties computed during housekeeping.
172
+ """
121
173
 
122
174
 
123
175
  class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
@@ -162,6 +214,7 @@ class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
162
214
  self,
163
215
  environment: Environment,
164
216
  sandbox: Sandbox,
217
+ duration: float,
165
218
  lifetime: float,
166
219
  error: BaseException | None
167
220
  ) -> None:
@@ -170,6 +223,7 @@ class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
170
223
  Args:
171
224
  environment: The environment.
172
225
  sandbox: The sandbox.
226
+ duration: The time spent on shutting down the sandbox.
173
227
  lifetime: The sandbox lifetime in seconds.
174
228
  error: The error that caused the sandbox to shutdown. If None, the
175
229
  sandbox shutdown normally.
@@ -206,7 +260,8 @@ class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
206
260
  sandbox: Sandbox,
207
261
  counter: int,
208
262
  duration: float,
209
- error: BaseException | None
263
+ error: BaseException | None,
264
+ **kwargs
210
265
  ) -> None:
211
266
  """Called when a sandbox finishes a round of housekeeping.
212
267
 
@@ -217,12 +272,20 @@ class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
217
272
  duration: The sandbox housekeeping duration in seconds.
218
273
  error: The error that caused the sandbox to housekeeping. If None, the
219
274
  sandbox housekeeping normally.
275
+ **kwargs: Sandbox-specific properties computed during housekeeping.
220
276
  """
221
277
 
222
278
 
223
279
  class EventHandler(_SandboxEventHandler):
224
280
  """Base class for event handlers of an environment."""
225
281
 
282
+ def on_environment_starting(self, environment: Environment) -> None:
283
+ """Called when the environment is getting started.
284
+
285
+ Args:
286
+ environment: The environment.
287
+ """
288
+
226
289
  def on_environment_start(
227
290
  self,
228
291
  environment: Environment,
@@ -243,7 +306,8 @@ class EventHandler(_SandboxEventHandler):
243
306
  environment: Environment,
244
307
  counter: int,
245
308
  duration: float,
246
- error: BaseException | None
309
+ error: BaseException | None,
310
+ **kwargs
247
311
  ) -> None:
248
312
  """Called when the environment finishes a round of housekeeping.
249
313
 
@@ -253,11 +317,25 @@ class EventHandler(_SandboxEventHandler):
253
317
  duration: The environment start duration in seconds.
254
318
  error: The error that failed the housekeeping. If None, the
255
319
  housekeeping succeeded.
320
+ **kwargs: Environment-specific properties computed during housekeeping.
321
+ """
322
+
323
+ def on_environment_shutting_down(
324
+ self,
325
+ environment: Environment,
326
+ offline_duration: float,
327
+ ) -> None:
328
+ """Called when the environment is shutting down.
329
+
330
+ Args:
331
+ environment: The environment.
332
+ offline_duration: The environment offline duration in seconds.
256
333
  """
257
334
 
258
335
  def on_environment_shutdown(
259
336
  self,
260
337
  environment: Environment,
338
+ duration: float,
261
339
  lifetime: float,
262
340
  error: BaseException | None
263
341
  ) -> None:
@@ -265,6 +343,7 @@ class EventHandler(_SandboxEventHandler):
265
343
 
266
344
  Args:
267
345
  environment: The environment.
346
+ duration: The environment shutdown duration in seconds.
268
347
  lifetime: The environment lifetime in seconds.
269
348
  error: The error that caused the environment to shutdown. If None, the
270
349
  environment shutdown normally.