studio / app /services /optimizer.py
Ava2lon's picture
Upload 46 files
3e93464 verified
Raw
History Blame
3.3 kB
from copy import deepcopy
from app.models.workflow import (
OptimizationResponse,
OptimizationSuggestion,
WorkflowDocument,
)
class WorkflowOptimizer:
def optimize(self, workflow: WorkflowDocument) -> OptimizationResponse:
optimized = deepcopy(workflow)
suggestions: list[OptimizationSuggestion] = []
http_nodes = [
node for node in optimized.nodes if node.data.type == "n8n-nodes-base.httpRequest"
]
for node in http_nodes:
options = node.data.parameters.setdefault("options", {})
if isinstance(options, dict) and "retry" not in options:
options.update({"retry": {"maxTries": 3, "waitBetweenTries": 1000}})
suggestions.append(
OptimizationSuggestion(
title="Add API retries",
description=f"Added bounded retry behavior to {node.data.label}.",
impact="high",
nodeIds=[node.id],
)
)
if not optimized.settings.get("saveExecutionProgress"):
optimized.settings["saveExecutionProgress"] = True
suggestions.append(
OptimizationSuggestion(
title="Enable execution recovery",
description="Save execution progress so long-running workflows can recover.",
impact="medium",
)
)
linear_pairs = []
for edge in optimized.edges:
source = next((node for node in optimized.nodes if node.id == edge.source), None)
target = next((node for node in optimized.nodes if node.id == edge.target), None)
if source and target and source.data.type == target.data.type == "n8n-nodes-base.set":
linear_pairs.append((source, target))
if linear_pairs:
suggestions.append(
OptimizationSuggestion(
title="Combine adjacent Edit Fields nodes",
description="Adjacent field transformations can be handled by one node.",
impact="medium",
nodeIds=[node.id for pair in linear_pairs for node in pair],
)
)
branches = {}
for edge in optimized.edges:
branches[edge.source] = branches.get(edge.source, 0) + 1
parallel = [node_id for node_id, count in branches.items() if count > 1]
if parallel:
suggestions.append(
OptimizationSuggestion(
title="Review parallel branches",
description="Independent branches can execute concurrently; merge only when required.",
impact="medium",
nodeIds=parallel,
)
)
if not suggestions:
suggestions.append(
OptimizationSuggestion(
title="Workflow is already compact",
description="No deterministic optimization could be applied safely.",
impact="low",
)
)
return OptimizationResponse(workflow=optimized, suggestions=suggestions)
optimizer = WorkflowOptimizer()