code: async def process_graph_input(graph, stream, value, rpc_executor):
      
  
      graph.sensor_log.push(stream, value)
  
      # FIXME: This should be specified in our device model
      if stream.important:
          associated_output = stream.associated_stream()
          graph.sensor_log.push(associated_output, value)
  
      to_check = deque([x for x in graph.roots])
  
      while len(to_check) > 0:
          node = to_check.popleft()
          if node.triggered():
              try:
                  results = node.process(rpc_executor, graph.mark_streamer)
                  for result in results:
                      if inspect.iscoroutine(result.value):
                          result.value = await asyncio.ensure_future(result.value)
  
                      result.raw_time = value.raw_time
                      graph.sensor_log.push(node.stream, result)
              except:
                  logging.getLogger(__name__).exception("Unhandled exception in graph node processing function for node %s", str(node))
  
              # If we generated any outputs, notify our downstream nodes
              # so that they are also checked to see if they should run.
              if len(results) > 0:
                  to_check.extend(node.outputs)
docs: Process an input through this sensor graph.
  
      The tick information in value should be correct and is transfered
      to all results produced by nodes acting on this tick.  This coroutine
      is an asyncio compatible version of SensorGraph.process_input()
  
      Args:
          stream (DataStream): The stream the input is part of
          value (IOTileReading): The value to process
          rpc_executor (RPCExecutor): An object capable of executing RPCs
              in case we need to do that.