code: def test_detached_actor_cleanup(ray_start_regular):
      @ray.remote
      class DetachedActor:
          def ping(self):
              return "pong"
  
      dup_actor_name = "actor"
  
      def create_and_kill_actor(actor_name):
          # Make sure same name is creatable after killing it.
          detached_actor = DetachedActor.options(
              lifetime="detached", name=actor_name
          ).remote()
          # Wait for detached actor creation.
          assert ray.get(detached_actor.ping.remote()) == "pong"
          del detached_actor
          assert ray.util.list_named_actors() == [dup_actor_name]
          detached_actor = ray.get_actor(dup_actor_name)
          ray.kill(detached_actor)
          # Wait until actor dies.
          actor_status = ray._private.state.actors(
              actor_id=detached_actor._actor_id.hex()
          )
          max_wait_time = 10
          wait_time = 0
          while actor_status["State"] != convert_actor_state(
              gcs_utils.ActorTableData.DEAD
          ):
              actor_status = ray._private.state.actors(
                  actor_id=detached_actor._actor_id.hex()
              )
              time.sleep(1.0)
              wait_time += 1
              if wait_time >= max_wait_time:
                  assert (
                      None
                  ), "It took too much time to kill an actor: {}".format(
                      detached_actor._actor_id
                  )
  
      create_and_kill_actor(dup_actor_name)
  
      # This shouldn't be broken because actor
      # name should have been cleaned up from GCS.
      create_and_kill_actor(dup_actor_name)
  
      address = ray_start_regular["address"]
      driver_script = """
  import ray
  import ray._private.gcs_utils as gcs_utils
  import time
  from ray._private.test_utils import convert_actor_state
  ray.init(address="{}", namespace="default_test_namespace")
  
  @ray.remote
  class DetachedActor:
      def ping(self):
          return "pong"
  
  # Make sure same name is creatable after killing it.
  detached_actor = DetachedActor.options(lifetime="detached", name="{}").remote()
  assert ray.get(detached_actor.ping.remote()) == "pong"
  ray.kill(detached_actor)
  # Wait until actor dies.
  actor_status = ray._private.state.actors(actor_id=detached_actor._actor_id.hex())
  max_wait_time = 10
  wait_time = 0
  while actor_status["State"] != convert_actor_state(gcs_utils.ActorTableData.DEAD): # noqa
      actor_status = ray._private.state.actors(actor_id=detached_actor._actor_id.hex())
      time.sleep(1.0)
      wait_time += 1
      if wait_time >= max_wait_time:
          assert None, (
              "It took too much time to kill an actor")
  """.format(
          address, dup_actor_name
      )
  
      run_string_as_driver(driver_script)
      # Make sure we can create a detached actor created/killed
      # at other scripts.
      create_and_kill_actor(dup_actor_name)
  
imports: import os
  import sys
  import time
  import numpy
  import pytest
  import ray
  import ray._private.gcs_utils
  from ray.util.state import list_actors
  import ray.cluster_utils
  from ray._private.test_utils import SignalActor, convert_actor_state, kill_actor_and_wait_for_failure, make_global_state_accessor, run_string_as_driver, wait_for_condition, wait_for_pid_to_exit
  from ray._private.ray_constants import gcs_actor_scheduling_enabled
  from ray.experimental.internal_kv import _internal_kv_get, _internal_kv_put
label_desc: Use image node_id 18 for calling a global function with example usage: test_detached_actor_cleanup(ray_start_regular) and returns: str