ElGraph.Ctx (ElGraph v0.3.0)

Copy Markdown View Source

노드 실행 컨텍스트. 모든 노드는 (state, ctx) 2-인자로 호출된다 (SPEC §3.2).

스트리밍 이벤트 방출, 협조적 취소 확인, 실행 메타데이터 접근의 통로다. 동적 인터럽트(interrupt/2)는 체크포인터와 함께 도입된다.

:assigns는 호출 단위(per-invocation)의 읽기 전용 컨텍스트로, invoke(graph, input, assigns: %{...})로 주입되어 모든 노드의 ctx.assigns로 전달된다.

Summary

Functions

협조적 취소 확인 (SPEC §3.9). 긴 루프나 스트림 처리 중 주기적으로 호출하라.

스트리밍 이벤트를 구독자에게 방출한다.

동적 인터럽트 (SPEC §3.6). 실행을 중단하고 호출자에게 payload와 함께 {:interrupted, info}를 반환하게 한다.

부수효과 있는 계산(LLM/툴 호출 등)을 key로 메모이즈한다 (replay-safe durability).

Types

t()

@type t() :: %ElGraph.Ctx{
  assigns: map(),
  cancel_flag: :atomics.atomics_ref() | nil,
  event_sink: pid() | nil,
  interrupt_counter: :counters.counters_ref() | nil,
  node: atom(),
  resume_values: [term()],
  step: non_neg_integer(),
  task_cache: :ets.tid() | nil,
  thread_id: String.t()
}

Functions

cancelled?(ctx)

@spec cancelled?(t()) :: boolean()

협조적 취소 확인 (SPEC §3.9). 긴 루프나 스트림 처리 중 주기적으로 호출하라.

ElGraph.Runner.cancel/2가 플래그를 세우면 true가 된다. 노드가 이를 무시하면 유예시간 후 brutal kill 된다.

emit(ctx, event)

@spec emit(t(), term()) :: :ok

스트리밍 이벤트를 구독자에게 방출한다.

invoke/3:event_sink 옵션으로 구독자 pid가 주어진 경우 {:el_graph_event, %{thread_id, step, node, event}} 메시지를 보낸다. 없으면 no-op.

interrupt(ctx, payload)

@spec interrupt(t(), term()) :: term()

동적 인터럽트 (SPEC §3.6). 실행을 중단하고 호출자에게 payload와 함께 {:interrupted, info}를 반환하게 한다.

ElGraph.resume(graph, resume: value)로 재개하면 노드가 처음부터 재실행되고, 이 함수는 이번에는 주입된 value를 반환한다. 한 노드 안의 여러 interrupt 호출은 호출 순서로 값과 매칭되므로 호출 순서는 결정적이어야 한다. interrupt 이전의 부수효과는 재실행 시 중복된다 — interrupt는 노드 초반에 두라.

memo(ctx, key, fun)

@spec memo(t(), term(), (-> value)) :: value when value: term()

부수효과 있는 계산(LLM/툴 호출 등)을 key로 메모이즈한다 (replay-safe durability).

처음 호출되면 fun을 실행해 결과를 이 실행(run)의 task 캐시에 기록하고 반환한다. 이후 같은 노드에서 같은 key로 다시 호출하거나(재시도), 인터럽트/크래시 후 재개 시 노드가 처음부터 재실행될 때fun을 다시 돌리지 않고 캐시된 값을 돌려준다 — LLM 호출 중복 비용·중복 부수효과를 막는다(Temporal Activity / LangGraph @task에 해당).

캐시는 체크포인트에 함께 영속되므로 재개(resume/resume_from)를 넘어 유효하다. 따라서 fun의 결과는 직렬화 가능해야 한다(pid/ref/port 금지 — 재개 시 무의미). task_cache가 없는 컨텍스트(예: 실행기 밖에서 노드 직접 호출)에서는 그냥 fun을 실행한다.

answer = Ctx.memo(ctx, :classify, fn -> LLM.chat(...) end)