code: def test_warning_for_dead_node(
      ray_start_cluster_2_nodes, error_pubsub
  ):
      cluster = ray_start_cluster_2_nodes
      cluster.wait_for_nodes()
      p = error_pubsub
  
      node_ids = {item["NodeID"] for item in ray.nodes()}
  
      # Try to make sure that the monitor has received at least one heartbeat
      # from the node.
      time.sleep(0.5)
  
      # Kill both raylets.
      cluster.list_all_nodes()[1].kill_raylet()
      cluster.list_all_nodes()[0].kill_raylet()
  
      # Check that we get warning messages for both raylets.
      errors = get_error_message(
          p, 2, ray_constants.REMOVED_NODE_ERROR, 40
      )
  
      # Extract the client IDs from the error messages. This will need to be
      # changed if the error message changes.
      warning_node_ids = {
          error["error_message"].split(" ")[5] for error in errors
      }
  
      assert node_ids == warning_node_ids
  
imports: import os
  import signal
  import sys
  import threading
  import time
  import numpy
  import pytest
  import ray
  import ray._private.ray_constants
  import ray._private.utils
  from ray._private.ray_constants import DEBUG_AUTOSCALING_ERROR
  from ray._private.test_utils import Semaphore, get_error_message, get_log_batch, init_error_pubsub, run_string_as_driver_nonblocking, wait_for_condition
  from ray.cluster_utils import cluster_not_supported
  from ray.experimental.internal_kv import _internal_kv_get
label_desc: Use image node_id 3 for calling a global function with example usage: test_warning_for_dead_node(ray_start_cluster_2_nodes, error_pubsub) without return types