threepp
C++20 기반 크로스플랫폼 3D 라이브러리, 파이썬 바인딩 및 three.js 수준 API 제공
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A domain specific language to build complex workflows
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Highway DSL is a Python-based domain-specific language for defining production-grade workflows with Temporal-style coordination patterns. It is part of the larger Highway project, an advanced workflow engine capable of running complex DAG-based workflows with durability guarantees.
Version 3.0.0 removes the
highway_dsl.mcp_client_servermodule, which was a client for the retired DSL generator web service. The DSL language, its operators and its JSON and YAML formats are unchanged from 2.2.0, so workflows written for 2.2.0 load and serialise the same way in 3.0.0.
This is a Long-Term Support (LTS) release consolidating all features from the 1.x series into a stable, production-ready API:
Replaces brittle TriggerRule-based joins with explicit coordination semantics:
from highway_dsl import WorkflowBuilder, JoinMode
builder = WorkflowBuilder("data_pipeline")
builder.task("start", "setup.init")
# Create parallel branches
builder.task("branch_a", "process.a", dependencies=["start"])
builder.task("branch_b", "process.b", dependencies=["start"])
builder.task("branch_c", "process.c", dependencies=["start"])
# Explicit join - wait for all branches to succeed
builder.join(
task_id="sync_gate",
join_tasks=["branch_a", "branch_b", "branch_c"],
join_mode=JoinMode.ALL_SUCCESS, # Fail fast if any branch fails
description="Wait for all extractions"
)
builder.task("finalize", "process.merge", dependencies=["sync_gate"])
Join Modes:
JoinMode.ALL_OF - Wait for all tasks to finish (any final state)JoinMode.ANY_OF - Complete when first task finishes (race condition)JoinMode.ALL_SUCCESS - Wait for all tasks to succeed (fail fast)JoinMode.ONE_SUCCESS - Complete when one task succeeds (fallback pattern)All operators can now store results in workflow context (not just TaskOperator):
# Now works for all operator types
builder.wait("sleep_5s", wait_for=Duration.seconds(5), result_key="sleep_result")
builder.emit_event("notify", event_name="done", result_key="emit_result")
builder.wait_for_event("wait", event_name="start", result_key="event_data")
Prevents runtime errors from typos in callback references:
builder.task("main", "func").on_success("handler_task")
workflow = builder.build() # Now validates "handler_task" exists!
Simplified time duration creation without datetime imports:
from highway_dsl import Duration
builder.wait("pause", wait_for=Duration.minutes(30))
builder.retry(delay=Duration.seconds(5))
builder.timeout(timeout=Duration.hours(1))
Set workflow description and version programmatically:
builder = WorkflowBuilder("my_workflow", version="2.0.0")
builder.set_description("Production ETL pipeline")
builder.set_version("2.1.0") # Update version later
Implements the Reflexive Loop pattern (Generate -> Verify -> Self-Correct) in a single atomic step:
builder.reflexive(
task_id="gen_code",
generator="tools.llm.call",
verifier="tools.python.run",
max_turns=3
)
More intuitive alias for the dependencies parameter:
builder.task("extract", "etl.extract", result_key="data")
builder.task("transform", "etl.transform", depends_on=["extract"]) # More readable
Simplified fork/join parallel execution with automatic join barrier:
builder.parallel_with_join(
"data_processing",
branches={
"process_users": lambda b: b.task("users", "process.users"),
"process_orders": lambda b: b.task("orders", "process.orders"),
},
timeout_seconds=120,
).task(
"aggregate", # Automatically depends on join task
"tools.aggregate",
)
Protect against cascading failures with per-activity circuit breakers:
from highway_dsl import CircuitBreakerPolicy
builder.task(
"call_external_api",
"api.fetch_data",
circuit_breaker_policy=CircuitBreakerPolicy(
failure_threshold=5, # Open after 5 failures
success_threshold=2, # Close after 2 successes
isolation_duration=timedelta(seconds=30),
)
)
PT<seconds>S) instead of duration:<seconds>This major feature release adds Airflow-parity features to enable production-grade workflows:
Define cron-based schedules directly in your workflow:
builder = (
WorkflowBuilder("daily_pipeline")
.set_schedule("0 2 * * *") # Run daily at 2 AM
.set_start_date(datetime(2025, 1, 1))
.set_catchup(False)
.add_tags("production", "daily")
.set_max_active_runs(1)
)
First-class support for event-driven workflows:
# Emit an event that other workflows can wait for
builder.emit_event(
"notify_completion",
event_name="pipeline_done",
payload={"status": "success"}
)
# Wait for an external event
builder.wait_for_event(
"wait_upstream",
event_name="data_ready",
timeout_seconds=3600
)
Durable success/failure handlers as first-class workflow nodes:
builder.task("risky_operation", "process.data")
builder.task("send_alert", "alerts.notify")
builder.on_failure("send_alert") # Runs if risky_operation fails
builder.task("cleanup", "cleanup.resources")
builder.on_success("cleanup") # Runs if risky_operation succeeds
Multi-branch routing with cleaner syntax than nested conditions:
builder.switch(
"route_by_status",
switch_on="{{data.status}}",
cases={
"approved": "approve_task",
"rejected": "reject_task",
"pending": "review_task"
},
default="unknown_handler"
)
Document your workflow inline:
builder.task(
"process",
"data.transform",
description="Transform raw data into analytics format"
)
Set a default retry policy for all tasks:
builder.set_default_retry_policy(
RetryPolicy(max_retries=3, delay=timedelta(seconds=60))
)
See examples/scheduled_event_workflow.py for a comprehensive example using all new features.
For implementers and advanced users, Highway DSL v1.1.0 includes a comprehensive 3,215-line RFC-style specification (spec.txt) modeled after IETF RFCs (RFC 2119, RFC 8259). This authoritative document provides:
Access the specification at /dsl/spec.txt in the repository.
graph TB
subgraph "Highway DSL v2.2.0 (LTS Stable)"
A[WorkflowBuilder<br/>Fluent API] --> B[Core Operators]
A --> C[Scheduling]
A --> D[Events]
A --> E[Error Handling]
B --> B1[Task]
B --> B2[Condition]
B --> B3[Parallel]
B --> B4[ForEach]
B --> B5[While]
B --> B6[Wait]
B --> B7[Switch]
B --> B8[Join]
B --> B9[Reflexive]
C --> C1[Cron Schedules]
C --> C2[Start Date]
C --> C3[Catchup]
C --> C4[Tags]
D --> D1[EmitEvent]
D --> D2[WaitForEvent]
E --> E1[RetryPolicy]
E --> E2[TimeoutPolicy]
E --> E3[Callbacks]
E --> E4[CircuitBreaker]
end
subgraph "Output Formats"
F[YAML]
G[JSON]
end
subgraph "Runtime Integration"
H[Absurd Runtime]
I[Airflow]
J[Temporal]
K[Custom Engines]
end
A --> F
A --> G
F --> H
F --> I
F --> J
F --> K
G --> H
G --> I
G --> J
G --> K
style A fill:#2563eb,stroke:#1e40af,color:#fff
style B fill:#8b5cf6,stroke:#7c3aed,color:#fff
style C fill:#10b981,stroke:#059669,color:#fff
style D fill:#f59e0b,stroke:#d97706,color:#fff
style E fill:#ef4444,stroke:#dc2626,color:#fff
WorkflowBuilder for defining workflows programmatically.Task - Basic workflow stepsActivity - Lightweight workflow steps (NEW in v2.0.2)Condition (if/else) - Conditional branchingParallel - Execute multiple branches simultaneouslyForEach - Iterate over collections with proper dependency managementWait - Pause execution for scheduled tasksWhile - Execute loops based on conditionsEmitEvent - Emit events for cross-workflow coordinationWaitForEvent - Wait for external events with timeoutSwitch - Multi-branch routing (switch/case)Join - Temporal-style explicit coordination with join modes (ALL_OF, ANY_OF, ALL_SUCCESS, ONE_SUCCESS)Reflexive - Atomic generation/verification loop (Sherlock pattern)pip install highway-dsl
Here's a simple example of how to define a workflow using the WorkflowBuilder:
from datetime import timedelta
from highway_dsl import WorkflowBuilder
workflow = (
WorkflowBuilder("simple_etl")
.task("extract", "etl.extract_data", result_key="raw_data")
.task(
"transform",
"etl.transform_data",
args=["{{raw_data}}"],
result_key="transformed_data",
)
.retry(max_retries=3, delay=timedelta(seconds=10))
.task("load", "etl.load_data", args=["{{transformed_data}}"])
.timeout(timeout=timedelta(minutes=30))
.wait("wait_next", timedelta(hours=24))
.task("cleanup", "etl.cleanup")
.build()
)
print(workflow.to_yaml())
from highway_dsl import WorkflowBuilder, RetryPolicy
from datetime import datetime, timedelta
# Production-ready e-commerce order workflow
workflow = (
WorkflowBuilder("order_processing")
.set_schedule("*/5 * * * *") # Run every 5 minutes
.set_start_date(datetime(2025, 1, 1))
.add_tags("production", "orders", "critical")
.set_default_retry_policy(RetryPolicy(max_retries=3, delay=timedelta(seconds=30)))
# Fetch pending orders
.task("fetch_orders", "orders.get_pending", result_key="orders")
# Process each order
.foreach(
"process_each_order",
items="{{orders}}",
loop_body=lambda b: (
b.task("validate", "orders.validate", args=["{{item}}"])
.task("charge_payment", "payments.charge", args=["{{item}}"],
result_key="payment_result")
.task("send_failure_email", "email.send_failure",
args=["{{item.customer_email}}"])
.on_failure("send_failure_email") # Alert on payment failure
.switch(
"route_by_amount",
switch_on="{{item.total}}",
cases={
"high": "priority_shipping", # > $500
"medium": "standard_shipping", # $100-500
"low": "economy_shipping" # < $100
},
default="standard_shipping"
)
)
)
# Emit completion event for analytics workflow
.emit_event(
"notify_analytics",
event_name="orders_processed_{{ds}}",
payload={"count": "{{orders.length}}", "timestamp": "{{run.started_at}}"}
)
.build()
)
This workflow demonstrates:
You can generate a Mermaid state diagram of your workflow using the to_mermaid method:
print(workflow.to_mermaid())
This will output a Mermaid diagram in the stateDiagram-v2 format, which can be used with a variety of tools to visualize your workflow.
A more complex example of a bank's end-of-day ETL process can be found in examples/bank_end_of_the_day_etl_workflow.py.
A mermaid diagram of this workflow can be found here.
from highway_dsl import WorkflowBuilder, RetryPolicy
from datetime import timedelta
builder = WorkflowBuilder("data_processing_pipeline")
builder.task("start", "workflows.tasks.initialize", result_key="init_data")
builder.task(
"validate",
"workflows.tasks.validate_data",
args=["{{init_data}}"],
result_key="validated_data",
)
builder.condition(
"check_quality",
condition="{{validated_data.quality_score}} > 0.8",
if_true=lambda b: b.task(
"high_quality_processing",
"workflows.tasks.advanced_processing",
args=["{{validated_data}}"],
retry_policy=RetryPolicy(max_retries=5, delay=timedelta(seconds=10), backoff_factor=2.0),
),
if_false=lambda b: b.task(
"standard_processing",
"workflows.tasks.basic_processing",
args=["{{validated_data}}"],
),
)
workflow = builder.build()
from highway_dsl import WorkflowBuilder
builder = WorkflowBuilder("qa_rework_workflow")
builder.task("start_qa", "workflows.tasks.start_qa", result_key="qa_results")
builder.while_loop(
"qa_rework_loop",
condition="{{qa_results.status}} == 'failed'",
loop_body=lambda b: b.task("perform_rework", "workflows.tasks.perform_rework").task(
"re_run_qa", "workflows.tasks.run_qa", result_key="qa_results"
),
)
builder.task("finalize_product", "workflows.tasks.finalize_product", dependencies=["qa_rework_loop"])
workflow = builder.build()
Fixed bug where foreach loops were incorrectly inheriting dependencies from containing parallel operators:
# This loop now properly encapsulates its internal tasks
builder.foreach(
"process_items",
items="{{data.items}}",
loop_body=lambda fb: fb.task("process_item", "processor.handle_item", args=["{{item.id}}"])
# Loop body tasks only have proper dependencies, not unwanted "grandparent" dependencies
)
from highway_dsl import RetryPolicy
from datetime import timedelta
builder.task(
"reliable_task",
"service.operation",
retry_policy=RetryPolicy(
max_retries=5,
delay=timedelta(seconds=10),
backoff_factor=2.0
)
)
from highway_dsl import TimeoutPolicy
from datetime import timedelta
builder.task(
"timed_task",
"service.operation",
timeout_policy=TimeoutPolicy(
timeout=timedelta(hours=1),
kill_on_timeout=True
)
)
Removed:
highway_dsl.mcp_client_server and the generator app under app/. They were clients of the DSL generator web service, which was retired on 2026-10-25.Unchanged: the DSL language, every operator, WorkflowBuilder, and the JSON and YAML formats from 2.2.0. highway_dsl.mcp_server (the highway-mcp-server command) stays.
New in 2.2.0:
child_workflows() / child_workflow() — spawn N child workflows as separate durable runs (each its own run, linked by parent_run_id), then await + collect their results via the run-id-independent counter-join. Each child is crash-recoverable and may itself spawn children (deep hierarchies) — unlike parallel() branch tasks, which run inline within the parent run.🎯 Long-Term Support Release:
New in 2.1.x:
depends_on alias for more readable dependency declarationsparallel_with_join method for simplified fork/join patternsCircuitBreakerPolicy for per-activity circuit breaker protectionConsolidated Features:
Developer Experience:
Airflow-Parity Features:
Event-Driven Features:
Production Features:
This is a stable release with important bug fixes and enhancements, including a critical fix for the ForEach operator dependency management issue.
To set up the development environment:
git clone https://github.com/your-username/highway.git
cd highway/dsl
python -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
pytest
mypy .
MIT License