Unexpected Behavior: Parallel Execution of Asymmetric Graph #151

Closed
opened 2026-02-15 17:16:24 -05:00 by yindo · 10 comments
Owner

Originally created by @jasontjahjono on GitHub (Dec 30, 2024).

I have this graph:

   B -----
 /         \
A           E 
 \         /
   C --- D

where B takes 5 seconds to run, C takes 2 seconds, and D takes 2 seconds. (i used timeout inside the nodes)
I expect the graph to run in 5 seconds, because I thought C and D can run in parallel while B is running (2+2 < 5 seconds).

However, in practice, it takes 7 seconds. B and C runs in parallel, but C waits for B to finish before moving into D.

Here's how I built the graph:

const workflow = new StateGraph(GraphState)
  .addNode('A', nodeA)
  .addNode('B', nodeB)
  .addNode('C', nodeC)
  .addNode('D', nodeD)
  .addNode('E', nodeE)
  .addEdge(START, 'A')
  .addEdge('A', 'B')
  .addEdge('A', 'C')
  .addEdge('C', 'D')
  .addEdge(['B', 'D'], 'E')
  .addEdge('E', END);

Here's the result:

NODE: In Node A (6ms elapsed)
NODE: In Node B (8ms elapsed)
NODE: In Node C (8ms elapsed)
NODE: In Node D (5016ms elapsed)
NODE: In Node E (7023ms elapsed)
RESULT { messages: [ 'A', 'B', 'C', 'D', 'E' ], startTime: 1735541316193 }

How do I make sure D does not wait for B to finish? I assumed this could be solved using subgraphs but I want to check if there's a more elegant solution than building a subgraph.

Originally created by @jasontjahjono on GitHub (Dec 30, 2024). I have this graph: ``` B ----- / \ A E \ / C --- D ``` where B takes 5 seconds to run, C takes 2 seconds, and D takes 2 seconds. (i used timeout inside the nodes) I expect the graph to run in 5 seconds, because I thought C and D can run in parallel while B is running (2+2 < 5 seconds). However, in practice, it takes 7 seconds. B and C runs in parallel, but C waits for B to finish before moving into D. Here's how I built the graph: ``` const workflow = new StateGraph(GraphState) .addNode('A', nodeA) .addNode('B', nodeB) .addNode('C', nodeC) .addNode('D', nodeD) .addNode('E', nodeE) .addEdge(START, 'A') .addEdge('A', 'B') .addEdge('A', 'C') .addEdge('C', 'D') .addEdge(['B', 'D'], 'E') .addEdge('E', END); ``` Here's the result: ``` NODE: In Node A (6ms elapsed) NODE: In Node B (8ms elapsed) NODE: In Node C (8ms elapsed) NODE: In Node D (5016ms elapsed) NODE: In Node E (7023ms elapsed) RESULT { messages: [ 'A', 'B', 'C', 'D', 'E' ], startTime: 1735541316193 } ``` How do I make sure D does not wait for B to finish? I assumed this could be solved using subgraphs but I want to check if there's a more elegant solution than building a subgraph.
yindo closed this issue 2026-02-15 17:16:24 -05:00
Author
Owner

@jacoblee93 commented on GitHub (Jan 2, 2025):

Hey @jasontjahjono, I believe we need #720 to land - you could then return a Send from node C.

Otherwise I don't think there's currently a way to get around the fact that nodes are processed one step at a time.

For now, subgraph is the best way to go. Will leave this open.

CC @nfcampos in case I'm missing something

@jacoblee93 commented on GitHub (Jan 2, 2025): Hey @jasontjahjono, I believe we need #720 to land - you could then return a `Send` from node `C`. Otherwise I don't think there's currently a way to get around the fact that nodes are processed one step at a time. For now, subgraph is the best way to go. Will leave this open. CC @nfcampos in case I'm missing something
Author
Owner

@oneWalker commented on GitHub (Mar 14, 2025):

@jacoblee93 hi,jacob. I also met this problem. But my problem is more complicated.
Here is my graph flow chain.

  • START -> A1 -> conditionA2 -> A31,A32 -> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END

When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot.

Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution.
For example:

  • START -> A1 -> conditionA2 -if->A32 -> Unit->END
  • START -> A1 -> conditionA2 -else-> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END
    The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team.
@oneWalker commented on GitHub (Mar 14, 2025): @jacoblee93 hi,jacob. I also met this problem. But my problem is more complicated. Here is my graph flow chain. - START -> A1 -> conditionA2 -> A31,A32 -> Unit->END - START -> B1 -> Unit->END - START -> C1 -> Unit->END When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot. Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution. For example: - START -> A1 -> conditionA2 -if->A32 -> Unit->END - START -> A1 -> conditionA2 -else-> Unit->END - START -> B1 -> Unit->END - START -> C1 -> Unit->END The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team.
Author
Owner

@oneWalker commented on GitHub (Mar 14, 2025):

I think a better practice is to define a special nodeType or special Edges, which don't need to wait all the pre-nodes results. We can control in node function by tag in state to decide wait or not. Follow on this, we don't need to achieve it in graph compile processing. Is there anyone having better advice? I'll appreciate it.

@oneWalker commented on GitHub (Mar 14, 2025): I think a better practice is to define a special nodeType or special Edges, which don't need to wait all the pre-nodes results. We can control in node function by tag in state to decide wait or not. Follow on this, we don't need to achieve it in graph compile processing. Is there anyone having better advice? I'll appreciate it.
Author
Owner

@oneWalker commented on GitHub (Mar 16, 2025):

The answer to the question is as follows:

  1. use addEdge('B', 'E') and addEdge('D', 'E') separately not addEdge(['B', 'D'], 'E')
  2. add a Set() named executedNodes. When the node is running
if(executedNodes.has(nodeName))return state; // skip the function。 it runs in langgraphjs,but not exectue in real.
else executedNodes.add(nodeName);
@oneWalker commented on GitHub (Mar 16, 2025): The answer to the question is as follows: 1. use `addEdge('B', 'E')` and `addEdge('D', 'E')` separately not `addEdge(['B', 'D'], 'E')` 2. add a `Set()` named executedNodes. When the node is running ```js if(executedNodes.has(nodeName))return state; // skip the function。 it runs in langgraphjs,but not exectue in real. else executedNodes.add(nodeName); ```
Author
Owner

@vianvio commented on GitHub (Mar 26, 2025):

@jacoblee93 hi,jacob. I also met this problem. But my problem is more complicated. Here is my graph flow chain.

  • START -> A1 -> conditionA2 -> A31,A32 -> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END

When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot.

Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution. For example:

  • START -> A1 -> conditionA2 -if->A32 -> Unit->END
  • START -> A1 -> conditionA2 -else-> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END
    The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team.

same to me. Getting issues with conditional edges

@vianvio commented on GitHub (Mar 26, 2025): > [@jacoblee93](https://github.com/jacoblee93) hi,jacob. I also met this problem. But my problem is more complicated. Here is my graph flow chain. > > * START -> A1 -> conditionA2 -> A31,A32 -> Unit->END > * START -> B1 -> Unit->END > * START -> C1 -> Unit->END > > When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot. > > Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution. For example: > > * START -> A1 -> conditionA2 -if->A32 -> Unit->END > * START -> A1 -> conditionA2 -else-> Unit->END > * START -> B1 -> Unit->END > * START -> C1 -> Unit->END > The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team. same to me. Getting issues with conditional edges
Author
Owner

@benjamincburns commented on GitHub (Mar 26, 2025):

Sorry for terse reply, responding from my phone.

The functional API works around this issue, for the most part.

You define when things execute, not us. If A is your entrypoint and the rest are tasks, you could kick off B&C, await C, then start D, and finish it off with a Promise.all([bProm, dProm]) before you kick off E.

@benjamincburns commented on GitHub (Mar 26, 2025): Sorry for terse reply, responding from my phone. The functional API works around this issue, for the most part. You define when things execute, not us. If A is your entrypoint and the rest are tasks, you could kick off B&C, await C, then start D, and finish it off with a `Promise.all([bProm, dProm])` before you kick off E.
Author
Owner

@benjamincburns commented on GitHub (Mar 26, 2025):

Also if you really want to keep the state schema that you get with StateGraph, I believe that you should still be able to invoke tasks from StateGraph nodes.

@benjamincburns commented on GitHub (Mar 26, 2025): Also if you really want to keep the state schema that you get with StateGraph, I believe that you should still be able to invoke tasks from StateGraph nodes.
Author
Owner

@oneWalker commented on GitHub (Apr 1, 2025):

@jacoblee93 hi,jacob. I also met this problem. But my problem is more complicated. Here is my graph flow chain.

  • START -> A1 -> conditionA2 -> A31,A32 -> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END

When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot.
Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution. For example:

  • START -> A1 -> conditionA2 -if->A32 -> Unit->END
  • START -> A1 -> conditionA2 -else-> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END
    The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team.

same to me. Getting issues with conditional edges

I solved it with state calculation and add a virtual node between the branch nodes and conditional Node. I will publish the implement in late days.

@oneWalker commented on GitHub (Apr 1, 2025): > > [@jacoblee93](https://github.com/jacoblee93) hi,jacob. I also met this problem. But my problem is more complicated. Here is my graph flow chain. > > > > * START -> A1 -> conditionA2 -> A31,A32 -> Unit->END > > * START -> B1 -> Unit->END > > * START -> C1 -> Unit->END > > > > When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot. > > Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution. For example: > > > > * START -> A1 -> conditionA2 -if->A32 -> Unit->END > > * START -> A1 -> conditionA2 -else-> Unit->END > > * START -> B1 -> Unit->END > > * START -> C1 -> Unit->END > > The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team. > > same to me. Getting issues with conditional edges I solved it with state calculation and add a virtual node between the branch nodes and conditional Node. I will publish the implement in late days.
Author
Owner

@oneWalker commented on GitHub (Apr 16, 2025):

@jacoblee93 hi,jacob. I also met this problem. But my problem is more complicated. Here is my graph flow chain.

  • START -> A1 -> conditionA2 -> A31,A32 -> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END

When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot.
Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution. For example:

  • START -> A1 -> conditionA2 -if->A32 -> Unit->END
  • START -> A1 -> conditionA2 -else-> Unit->END
  • START -> B1 -> Unit->END
  • START -> C1 -> Unit->END
    The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team.

same to me. Getting issues with conditional edges

@vianvio, here is my article about the solution to the problem. I hope it can be useful for you.
https://dev.to/techwalker/dynamic-pruning-strategy-in-langgraphjs-4ed5

@oneWalker commented on GitHub (Apr 16, 2025): > > [@jacoblee93](https://github.com/jacoblee93) hi,jacob. I also met this problem. But my problem is more complicated. Here is my graph flow chain. > > > > * START -> A1 -> conditionA2 -> A31,A32 -> Unit->END > > * START -> B1 -> Unit->END > > * START -> C1 -> Unit->END > > > > When I run the flow, I expect only one edge between A31-Unit, and A32-Unit. But the current library will wait for both of them. Is there anyway that i can make contribution on this. Or could you point the core code about this? Thanks a lot. > > Apart from this, I also have another question is when the conditionNode is linked to the next node, cuz the next node will be executed immediately without wait for parallel nodes execution. For example: > > > > * START -> A1 -> conditionA2 -if->A32 -> Unit->END > > * START -> A1 -> conditionA2 -else-> Unit->END > > * START -> B1 -> Unit->END > > * START -> C1 -> Unit->END > > The Unit will be executed after conditionA2 is finished without waiting B1 and C1. Looking forward to the good messages from you team. > > same to me. Getting issues with conditional edges @vianvio, here is my article about the solution to the problem. I hope it can be useful for you. https://dev.to/techwalker/dynamic-pruning-strategy-in-langgraphjs-4ed5
Author
Owner

@dqbd commented on GitHub (May 20, 2025):

Thanks for sharing! Seems like the issue has been solved, so closing. Feel free to reopen if needed

@dqbd commented on GitHub (May 20, 2025): Thanks for sharing! Seems like the issue has been solved, so closing. Feel free to reopen if needed
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#151