langfun 0.1.2.dev202509290805__py3-none-any.whl → 0.1.2.dev202509300805__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.

@@ -221,7 +221,7 @@ class BaseEnvironment(interface.Environment):
221
221
  self._sandbox_pool = [None] * self.min_pool_size
222
222
  for i, sandbox, _ in lf.concurrent_map(
223
223
  lambda i: self._bring_up_sandbox_with_retry(
224
- sandbox_id=str(i), shutdown_env_upon_outage=False
224
+ sandbox_id=f'{i}:0', shutdown_env_upon_outage=False
225
225
  ),
226
226
  range(self.min_pool_size),
227
227
  silence_on_errors=None,
@@ -335,6 +335,7 @@ class BaseEnvironment(interface.Environment):
335
335
  f'it is in {self._status.value!r} status.'
336
336
  )
337
337
 
338
+ self.on_starting()
338
339
  starting_time = time.time()
339
340
  try:
340
341
  self._start()
@@ -359,11 +360,12 @@ class BaseEnvironment(interface.Environment):
359
360
 
360
361
  self._set_status(self.Status.SHUTTING_DOWN)
361
362
 
363
+ shutting_down_time = time.time()
362
364
  try:
363
365
  self._shutdown()
364
- self.on_shutdown()
366
+ self.on_shutdown(duration=time.time() - shutting_down_time)
365
367
  except BaseException as e: # pylint: disable=broad-except
366
- self.on_shutdown(error=e)
368
+ self.on_shutdown(duration=time.time() - shutting_down_time, error=e)
367
369
  raise e
368
370
 
369
371
  #
@@ -412,7 +414,8 @@ class BaseEnvironment(interface.Environment):
412
414
  else:
413
415
  try:
414
416
  sandbox = self._bring_up_sandbox(
415
- sandbox_id=str(self._increment_sandbox_id()), set_acquired=True,
417
+ sandbox_id=f'{self._increment_sandbox_id()}:0',
418
+ set_acquired=True,
416
419
  )
417
420
  # Append is atomic and does not require locking.
418
421
  self._sandbox_pool.append(sandbox)
@@ -544,8 +547,9 @@ class BaseEnvironment(interface.Environment):
544
547
  len(dead_pool_indices),
545
548
  )
546
549
  def _replace(i: int):
550
+ generation = int(self._sandbox_pool[i].id.sandbox_id.split(':')[1])
547
551
  self._sandbox_pool[i] = self._bring_up_sandbox_with_retry(
548
- str(i), shutdown_env_upon_outage=False
552
+ f'{i}:{generation + 1}', shutdown_env_upon_outage=False
549
553
  )
550
554
 
551
555
  # TODO(daiyip): Consider to loose the condition to allow some dead
@@ -564,6 +568,11 @@ class BaseEnvironment(interface.Environment):
564
568
  # Event handlers subclasses can override.
565
569
  #
566
570
 
571
+ def on_starting(self) -> None:
572
+ """Called when the environment is getting started."""
573
+ for handler in self.event_handlers:
574
+ handler.on_environment_starting(self)
575
+
567
576
  def on_start(
568
577
  self,
569
578
  duration: float, error: BaseException | None = None
@@ -582,8 +591,11 @@ class BaseEnvironment(interface.Environment):
582
591
  for handler in self.event_handlers:
583
592
  handler.on_environment_housekeep(self, housekeep_counter, duration, error)
584
593
 
585
- def on_shutdown(self, error: BaseException | None = None) -> None:
594
+ def on_shutdown(
595
+ self,
596
+ duration: float,
597
+ error: BaseException | None = None) -> None:
586
598
  """Called when the environment is shutdown."""
587
599
  lifetime = (time.time() - self.start_time) if self.start_time else 0.0
588
600
  for handler in self.event_handlers:
589
- handler.on_environment_shutdown(self, lifetime, error)
601
+ handler.on_environment_shutdown(self, duration, lifetime, error)
@@ -418,6 +418,7 @@ class BaseSandbox(interface.Sandbox):
418
418
  self.end_session(shutdown_sandbox=True)
419
419
  return
420
420
 
421
+ shutting_down_time = time.time()
421
422
  self._set_status(interface.Sandbox.Status.SHUTTING_DOWN)
422
423
 
423
424
  if (self._housekeep_thread is not None
@@ -429,7 +430,10 @@ class BaseSandbox(interface.Sandbox):
429
430
  try:
430
431
  self._shutdown()
431
432
  self._set_status(interface.Sandbox.Status.OFFLINE)
432
- self.on_shutdown(teardown_error)
433
+ self.on_shutdown(
434
+ duration=time.time() - shutting_down_time,
435
+ error=teardown_error
436
+ )
433
437
  shutdown_error = None
434
438
  except BaseException as e: # pylint: disable=broad-except
435
439
  shutdown_error = e
@@ -439,7 +443,10 @@ class BaseSandbox(interface.Sandbox):
439
443
  '[%s]: Sandbox shutdown with error: %s',
440
444
  self.id, e
441
445
  )
442
- self.on_shutdown(teardown_error or shutdown_error)
446
+ self.on_shutdown(
447
+ duration=time.time() - shutting_down_time,
448
+ error=teardown_error or shutdown_error
449
+ )
443
450
 
444
451
  # We raise non-state errors to the user following timely order, so the user
445
452
  # code could be surfaced and handled properly.
@@ -591,6 +598,7 @@ class BaseSandbox(interface.Sandbox):
591
598
  # Set sandbox status to EXITING_SESSION to avoid re-entry.
592
599
  self._set_status(self.Status.EXITING_SESSION)
593
600
  shutdown_sandbox = shutdown_sandbox or not self.reusable
601
+ ending_time = time.time()
594
602
 
595
603
  # Teardown features for the current session.
596
604
  end_session_error = self._end_session()
@@ -617,7 +625,9 @@ class BaseSandbox(interface.Sandbox):
617
625
  self.shutdown()
618
626
 
619
627
  # End session before setting up the next session.
620
- self.on_session_end(previous_session_id)
628
+ self.on_session_end(
629
+ previous_session_id, duration=time.time() - ending_time
630
+ )
621
631
 
622
632
  # Mark the sandbox as setting up to prevent it from being acquired by
623
633
  # other threads.
@@ -628,7 +638,9 @@ class BaseSandbox(interface.Sandbox):
628
638
  threading.Thread(target=_setup_next_session).start()
629
639
  else:
630
640
  # End session before reporting sandbox status change.
631
- self.on_session_end(previous_session_id)
641
+ self.on_session_end(
642
+ previous_session_id, duration=time.time() - ending_time
643
+ )
632
644
 
633
645
  # If shutdown is requested, mark the sandbox as acquired to prevent it
634
646
  # from being acquired by other threads.
@@ -639,7 +651,11 @@ class BaseSandbox(interface.Sandbox):
639
651
 
640
652
  # Otherwise, shutdown the sandbox.
641
653
  else:
642
- self.on_session_end(previous_session_id, self.state_errors[0])
654
+ self.on_session_end(
655
+ previous_session_id,
656
+ duration=time.time() - ending_time,
657
+ error=self.state_errors[0]
658
+ )
643
659
  self._set_status(interface.Sandbox.Status.ACQUIRED)
644
660
  shutdown_sandbox = True
645
661
 
@@ -762,14 +778,20 @@ class BaseSandbox(interface.Sandbox):
762
778
  time.time() - self._status_start_time
763
779
  )
764
780
 
765
- def on_shutdown(self, error: BaseException | None = None) -> None:
781
+ def on_shutdown(
782
+ self,
783
+ duration: float,
784
+ error: BaseException | None = None
785
+ ) -> None:
766
786
  """Called when the sandbox is shutdown."""
767
787
  if self._start_time is None:
768
788
  lifetime = 0.0
769
789
  else:
770
790
  lifetime = time.time() - self._start_time
771
791
  for handler in self._event_handlers:
772
- handler.on_sandbox_shutdown(self.environment, self, lifetime, error)
792
+ handler.on_sandbox_shutdown(
793
+ self.environment, self, duration, lifetime, error
794
+ )
773
795
 
774
796
  def on_housekeep(
775
797
  self,
@@ -880,13 +902,14 @@ class BaseSandbox(interface.Sandbox):
880
902
  def on_session_end(
881
903
  self,
882
904
  session_id: str,
905
+ duration: float,
883
906
  error: BaseException | None = None
884
907
  ) -> None:
885
908
  """Called when the user session ends."""
886
909
  lifetime = time.time() - self._session_start_time
887
910
  for handler in self._event_handlers:
888
911
  handler.on_session_end(
889
- self.environment, self, session_id, lifetime, error
912
+ self.environment, self, session_id, duration, lifetime, error
890
913
  )
891
914
 
892
915
 
langfun/env/base_test.py CHANGED
@@ -381,34 +381,34 @@ class SandboxStatusTests(unittest.TestCase):
381
381
  self.assertEqual(
382
382
  self.event_handler.logs,
383
383
  [
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',
384
+ '[testing-env/0:0] shell: "feature1" setup',
385
+ '[testing-env/0:0/feature1] feature setup',
386
+ '[testing-env/0:0] shell: "feature2" setup',
387
+ '[testing-env/0:0/feature2] feature setup',
388
+ '[testing-env/0:0] shell: "feature1" setup session',
389
+ '[testing-env/0:0/feature1] feature setup session',
390
+ '[testing-env/0:0] shell: "feature2" setup session',
391
+ '[testing-env/0:0/feature2] feature setup session',
392
+ '[testing-env/0:0] created -> ready',
393
+ '[testing-env/0:0] sandbox started',
394
394
  '[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'
395
+ '[testing-env/0:0] ready -> acquired',
396
+ '[testing-env/0:0] acquired -> setting_up',
397
+ '[testing-env/0:0] setting_up -> in_session',
398
+ "[testing-env/0:0] session 'session1' started",
399
+ '[testing-env/0:0/session1] shell: echo "hello"',
400
+ '[testing-env/0:0] in_session -> exiting_session',
401
+ '[testing-env/0:0/session1] shell: "feature1" teardown session',
402
+ '[testing-env/0:0/feature1] feature teardown session',
403
+ '[testing-env/0:0/session1] shell: "feature2" teardown session',
404
+ '[testing-env/0:0/feature2] feature teardown session',
405
+ "[testing-env/0:0] session 'session1' ended",
406
+ '[testing-env/0:0] exiting_session -> setting_up',
407
+ '[testing-env/0:0] shell: "feature1" setup session',
408
+ '[testing-env/0:0/feature1] feature setup session',
409
+ '[testing-env/0:0] shell: "feature2" setup session',
410
+ '[testing-env/0:0/feature2] feature setup session',
411
+ '[testing-env/0:0] setting_up -> ready'
412
412
  ]
413
413
  )
414
414
 
@@ -440,17 +440,19 @@ class SandboxStatusTests(unittest.TestCase):
440
440
  self.assertEqual(
441
441
  event_handler.logs,
442
442
  [
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'
443
+ # pylint: disable=line-too-long
444
+ '[testing-env/0:0] in_session -> exiting_session',
445
+ '[testing-env/0:0/session1] shell: "test_feature" teardown session',
446
+ '[testing-env/0:0/test_feature] feature teardown session',
447
+ "[testing-env/0:0] session 'session1' ended",
448
+ '[testing-env/0:0] exiting_session -> setting_up',
449
+ '[testing-env/0:0/test_feature] feature setup session with SandboxStateError', # pylint: disable=line-too-long
450
+ '[testing-env/0:0] setting_up -> shutting_down',
451
+ '[testing-env/0:0] shell: "test_feature" teardown',
452
+ '[testing-env/0:0/test_feature] feature teardown',
453
+ '[testing-env/0:0] shutting_down -> offline',
454
+ '[testing-env/0:0] sandbox shutdown'
455
+ # pylint: enable=line-too-long
454
456
  ]
455
457
  )
456
458
 
@@ -493,10 +495,10 @@ class SandboxStatusTests(unittest.TestCase):
493
495
  self.assertEqual(
494
496
  self.event_handler.logs,
495
497
  [
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',
498
+ '[testing-env/0:0] sandbox started with SandboxStateError',
499
+ '[testing-env/0:0] created -> shutting_down',
500
+ '[testing-env/0:0] shutting_down -> offline',
501
+ '[testing-env/0:0] sandbox shutdown',
500
502
  '[testing-env] environment started with EnvironmentOutageError',
501
503
  '[testing-env] environment shutdown'
502
504
  ]
@@ -569,24 +571,24 @@ class SandboxStatusTests(unittest.TestCase):
569
571
  self.assertEqual(
570
572
  self.event_handler.logs,
571
573
  [
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',
574
+ '[testing-env/0:0] shell: "feature1" setup',
575
+ '[testing-env/0:0/feature1] feature setup',
576
+ '[testing-env/0:0] shell: "feature2" setup',
577
+ '[testing-env/0:0/feature2] feature setup',
578
+ '[testing-env/0:0] shell: "feature1" setup session',
579
+ '[testing-env/0:0/feature1] feature setup session',
580
+ '[testing-env/0:0] shell: "feature2" setup session',
581
+ '[testing-env/0:0/feature2] feature setup session',
582
+ '[testing-env/0:0] created -> ready',
583
+ '[testing-env/0:0] sandbox started',
582
584
  '[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',
585
+ '[testing-env/0:0] ready -> shutting_down',
586
+ '[testing-env/0:0] shell: "feature1" teardown',
587
+ '[testing-env/0:0/feature1] feature teardown',
588
+ '[testing-env/0:0] shell: "feature2" teardown',
589
+ '[testing-env/0:0/feature2] feature teardown',
590
+ '[testing-env/0:0] shutting_down -> offline',
591
+ '[testing-env/0:0] sandbox shutdown with ValueError',
590
592
  '[testing-env] environment shutdown with ValueError'
591
593
  ]
592
594
  )
@@ -998,27 +1000,27 @@ class SandboxStatusTests(unittest.TestCase):
998
1000
  self.assertEqual(
999
1001
  self.event_handler.logs,
1000
1002
  [
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',
1003
+ '[testing-env/0:0] shell: "feature1" setup',
1004
+ '[testing-env/0:0/feature1] feature setup',
1005
+ '[testing-env/0:0] shell: "feature1" setup session',
1006
+ '[testing-env/0:0/feature1] feature setup session',
1007
+ '[testing-env/0:0] created -> ready',
1008
+ '[testing-env/0:0] sandbox started',
1007
1009
  '[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',
1010
+ '[testing-env/0:0] ready -> acquired',
1011
+ '[testing-env/0:0] acquired -> setting_up',
1012
+ '[testing-env/0:0] setting_up -> in_session',
1013
+ "[testing-env/0:0] session 'session1' started",
1014
+ '[testing-env/0:0/session1] shell: echo foo with ValueError',
1015
+ '[testing-env/0:0/session1] shell: echo bar',
1016
+ '[testing-env/0:0] in_session -> exiting_session',
1017
+ '[testing-env/0:0/session1] shell: "feature1" teardown session',
1018
+ '[testing-env/0:0/feature1] feature teardown session',
1019
+ "[testing-env/0:0] session 'session1' ended",
1020
+ '[testing-env/0:0] exiting_session -> setting_up',
1021
+ '[testing-env/0:0] shell: "feature1" setup session',
1022
+ '[testing-env/0:0/feature1] feature setup session',
1023
+ '[testing-env/0:0] setting_up -> ready',
1022
1024
  ]
1023
1025
  )
1024
1026
 
@@ -1039,29 +1041,31 @@ class SandboxStatusTests(unittest.TestCase):
1039
1041
  self.assertEqual(
1040
1042
  self.event_handler.logs,
1041
1043
  [
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',
1044
+ # pylint: disable=line-too-long
1045
+ '[testing-env/0:0] shell: "feature1" setup',
1046
+ '[testing-env/0:0/feature1] feature setup',
1047
+ '[testing-env/0:0] shell: "feature1" setup session',
1048
+ '[testing-env/0:0/feature1] feature setup session',
1049
+ '[testing-env/0:0] created -> ready',
1050
+ '[testing-env/0:0] sandbox started',
1048
1051
  '[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',
1052
+ '[testing-env/0:0] ready -> acquired',
1053
+ '[testing-env/0:0] acquired -> setting_up',
1054
+ '[testing-env/0:0] setting_up -> in_session',
1055
+ "[testing-env/0:0] session 'session1' started",
1056
+ '[testing-env/0:0/session1] shell: echo foo with RuntimeError',
1057
+ '[testing-env/0:0] in_session -> exiting_session',
1058
+ '[testing-env/0:0/session1] shell: "feature1" teardown session',
1059
+ '[testing-env/0:0/feature1] feature teardown session',
1060
+ "[testing-env/0:0] session 'session1' ended with SandboxStateError",
1061
+ '[testing-env/0:0] exiting_session -> acquired',
1062
+ '[testing-env/0:0] acquired -> shutting_down',
1063
+ '[testing-env/0:0] shell: "feature1" teardown',
1064
+ '[testing-env/0:0/feature1] feature teardown',
1065
+ '[testing-env/0:0] shutting_down -> offline',
1066
+ '[testing-env/0:0] sandbox shutdown',
1067
+ '[testing-env/0:0] shell: echo bar',
1068
+ # pylint: enable=line-too-long
1065
1069
  ]
1066
1070
  )
1067
1071
 
@@ -1107,12 +1111,15 @@ class SandboxActivityTests(unittest.TestCase):
1107
1111
  self.assertEqual(sb.status, sb.Status.OFFLINE)
1108
1112
 
1109
1113
  def test_housekeep_error(self):
1114
+ event_handler = TestingEventHandler(log_housekeep=False)
1110
1115
  env = TestingEnvironment(
1111
1116
  features={'test_feature': TestingFeature(housekeep_interval=0)},
1112
1117
  pool_size=1,
1118
+ housekeep_interval=1.0,
1113
1119
  outage_grace_period=0,
1114
- outage_retry_interval=0,
1120
+ outage_retry_interval=0.1,
1115
1121
  sandbox_keepalive_interval=0,
1122
+ event_handlers=[event_handler],
1116
1123
  )
1117
1124
  with env:
1118
1125
  with env.sandbox('session1') as sb:
@@ -1129,6 +1136,31 @@ class SandboxActivityTests(unittest.TestCase):
1129
1136
  ):
1130
1137
  time.sleep(0.01)
1131
1138
  self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
1139
+ env.wait_for_housekeeping()
1140
+ self.assertEqual(
1141
+ event_handler.logs,
1142
+ [
1143
+ '[testing-env/0:0] shell: "test_feature" setup',
1144
+ '[testing-env/0:0/test_feature] feature setup',
1145
+ '[testing-env/0:0] shell: "test_feature" setup session',
1146
+ '[testing-env/0:0] sandbox started',
1147
+ '[testing-env] environment started',
1148
+ "[testing-env/0:0] session 'session1' started",
1149
+ '[testing-env/0:0/session1] shell: "test_feature" teardown session',
1150
+ "[testing-env/0:0] session 'session1' ended with SandboxStateError",
1151
+ '[testing-env/0:0] shell: "test_feature" teardown',
1152
+ '[testing-env/0:0/test_feature] feature teardown',
1153
+ '[testing-env/0:0] sandbox shutdown',
1154
+ '[testing-env/0:1] shell: "test_feature" setup',
1155
+ '[testing-env/0:1/test_feature] feature setup',
1156
+ '[testing-env/0:1] shell: "test_feature" setup session',
1157
+ '[testing-env/0:1] sandbox started',
1158
+ '[testing-env/0:1] shell: "test_feature" teardown',
1159
+ '[testing-env/0:1/test_feature] feature teardown',
1160
+ '[testing-env/0:1] sandbox shutdown',
1161
+ '[testing-env] environment shutdown'
1162
+ ]
1163
+ )
1132
1164
 
1133
1165
  def test_remove_event_handler(self):
1134
1166
  env = TestingEnvironment(
@@ -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.
@@ -162,6 +164,7 @@ class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
162
164
  self,
163
165
  environment: Environment,
164
166
  sandbox: Sandbox,
167
+ duration: float,
165
168
  lifetime: float,
166
169
  error: BaseException | None
167
170
  ) -> None:
@@ -170,6 +173,7 @@ class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
170
173
  Args:
171
174
  environment: The environment.
172
175
  sandbox: The sandbox.
176
+ duration: The time spent on shutting down the sandbox.
173
177
  lifetime: The sandbox lifetime in seconds.
174
178
  error: The error that caused the sandbox to shutdown. If None, the
175
179
  sandbox shutdown normally.
@@ -223,6 +227,13 @@ class _SandboxEventHandler(_FeatureEventHandler, _SessionEventHandler):
223
227
  class EventHandler(_SandboxEventHandler):
224
228
  """Base class for event handlers of an environment."""
225
229
 
230
+ def on_environment_starting(self, environment: Environment) -> None:
231
+ """Called when the environment is getting started.
232
+
233
+ Args:
234
+ environment: The environment.
235
+ """
236
+
226
237
  def on_environment_start(
227
238
  self,
228
239
  environment: Environment,
@@ -258,6 +269,7 @@ class EventHandler(_SandboxEventHandler):
258
269
  def on_environment_shutdown(
259
270
  self,
260
271
  environment: Environment,
272
+ duration: float,
261
273
  lifetime: float,
262
274
  error: BaseException | None
263
275
  ) -> None:
@@ -265,6 +277,7 @@ class EventHandler(_SandboxEventHandler):
265
277
 
266
278
  Args:
267
279
  environment: The environment.
280
+ duration: The environment shutdown duration in seconds.
268
281
  lifetime: The environment lifetime in seconds.
269
282
  error: The error that caused the environment to shutdown. If None, the
270
283
  environment shutdown normally.