code: def test_basic_reconstruction_actor_constructor(
      config, ray_start_cluster, reconstruction_enabled
  ):
      # Workaround to reset the config to the default value.
      if not reconstruction_enabled:
          config["lineage_pinning_enabled"] = False
  
      cluster = ray_start_cluster
      # Head node with no resources.
      cluster.add_node(
          num_cpus=0,
          _system_config=config,
          enable_object_reconstruction=reconstruction_enabled,
      )
      ray.init(address=cluster.address)
      # Node to place the initial object.
      node_to_kill = cluster.add_node(
          num_cpus=1,
          resources={"node1": 1},
          object_store_memory=10**8,
      )
      cluster.add_node(
          num_cpus=1,
          resources={"node2": 1},
          object_store_memory=10**8,
      )
      cluster.wait_for_nodes()
  
      @ray.remote(max_retries=1 if reconstruction_enabled else 0)
      def large_object():
          return np.zeros(10**7, dtype=np.uint8)
  
      # Both the constructor and a method depend on the large object.
      @ray.remote(max_restarts=-1)
      class Actor:
          def __init__(self, x):
              pass
  
          def dependent_task(self, x):
              return
  
          def pid(self):
              return os.getpid()
  
      obj = large_object.options(resources={"node1": 1}).remote()
      a = Actor.options(resources={"node1": 1}).remote(obj)
      ray.get(a.dependent_task.remote(obj))
      pid = ray.get(a.pid.remote())
  
      # Workaround to kill the actor process too since there is a bug where the
      # actor's plasma client hangs after the plasma store has exited.
      os.kill(pid, SIGKILL)
  
      cluster.remove_node(node_to_kill, allow_graceful=False)
      cluster.add_node(
          num_cpus=1,
          resources={"node1": 1},
          object_store_memory=10**8,
      )
  
      wait_for_pid_to_exit(pid)
  
      # Wait for the actor to restart.
      def probe():
          try:
              ray.get(a.dependent_task.remote(obj))
              return True
          except ray.exceptions.RayActorError as e:
              return e.actor_init_failed
          except (
              ray.exceptions.RayTaskError,
              ray.exceptions.ObjectLostError,
          ):
              return True
  
      wait_for_condition(probe)
  
      if reconstruction_enabled:
          ray.get(a.dependent_task.remote(obj))
      else:
          with pytest.raises(ray.exceptions.RayActorError) as exc_info:
              x = a.dependent_task.remote(obj)
              print(x)
              ray.get(x)
          exc = str(exc_info.value)
          assert "arguments" in exc
          assert "ObjectLostError" in exc
  
file_path: ray/python/ray/tests/test_reconstruction.py
imports: import os
  import signal
  import sys
  import time
  import numpy
  import pytest
  import ray
  from ray._private.test_utils import wait_for_condition, wait_for_pid_to_exit
label_desc: Use image node_id 8 for calling a global function with example usage: test_basic_reconstruction_actor_constructor(config, ray_start_cluster, reconstruction_enabled) and returns: np, os, True, e, True