NeoGraph 0.16.0
A C++20 Graph Agent Engine Library — LangGraph for C++
Loading...
Searching...
No Matches
neograph::graph::CancelToken Class Reference

Cooperative cancel primitive shared between caller and engine. More...

#include <cancel.h>

Public Member Functions

asio::any_io_executor bind_executor (asio::any_io_executor ex)
 Bind a serial executor that owns this token's cancellation_signal.
 
void cancel () noexcept
 Request cancellation.
 
std::shared_ptr< CancelToken > fork ()
 Create a child token that cascades from this one.
 
bool is_cancelled () const noexcept
 Thread-safe observation of the same state used by subscriptions.
 
asio::cancellation_slot slot () noexcept
 Cancellation slot for binding to a coroutine via asio::bind_cancellation_slot at co_spawn.
 
std::stop_token stop_token () const noexcept
 Native cancellation subscriptions independent of Asio slot ownership.
 
void throw_if_cancelled (const std::string &detail={}) const
 Throws CancelledException if cancelled.
 
void unbind_executor () noexcept
 Detach the serial executor after every bound operation drained.
 

Detailed Description

Cooperative cancel primitive shared between caller and engine.

One stop source owns the cancellation state; Asio signals retain their serial-executor contract. Native subscriptions need no executor binding. Pass via RunConfig::cancel_token (shared_ptr) to opt in. Re-entrant: cancel() is idempotent; callers may share the token across concurrent runs to fan out a single abort.

Definition at line 82 of file cancel.h.

Member Function Documentation

◆ bind_executor()

asio::any_io_executor neograph::graph::CancelToken::bind_executor ( asio::any_io_executor  ex)
inline

Bind a serial executor that owns this token's cancellation_signal.

Returns the serial executor that must initiate every co_spawn bound to slot(). Callers running on another executor first hop with co_await asio::post(bound, asio::use_awaitable). This keeps slot connection/destruction and emit() on one strand; generic multi-threaded executors do not provide that guarantee themselves.

If cancel() has already been requested, bind schedules an immediate emit. The coroutine started on the returned executor must still check throw_if_cancelled() before beginning I/O, because that queued emit may precede its slot connection.

Warning
Outside GraphEngine, the caller owns the lifetime contract: keep a directly constructed token alive until the bound executor drains.

Definition at line 181 of file cancel.h.

◆ cancel()

void neograph::graph::CancelToken::cancel ( )
inlinenoexcept

Request cancellation.

Thread-safe, idempotent.

Sets the stop state before synchronously invoking native subscriptions, then posts the Asio signal onto its bound serial executor. Subscriptions run without either token mutex held and must not throw.

Safe before bind_executor(): native stop callbacks still run, and a subsequently bound coroutine observes the same eager stop state.

Engine-created operation children retain themselves until a posted emit executes. A directly constructed token has no such ownership source: callers that use bind_executor() themselves must keep that token alive until the executor has drained all posted work.

Definition at line 104 of file cancel.h.

◆ fork()

std::shared_ptr< CancelToken > neograph::graph::CancelToken::fork ( )
inline

Create a child token that cascades from this one.

Each child has its own cancellation_signal, so concurrent consumers (such as multi-Send fan-out workers bridging HTTP coroutines through run_sync with their own io_context) never overwrite each other's cancellation slot. Calling cancel() on the parent walks the live children list and cascades — every child's signal fires on its own bound executor.

Lifetime / ownership: returns a shared_ptr<CancelToken>; the parent stores a weak_ptr so a forked child that goes out of scope is automatically pruned from the cascade list on the next cancel() / fork(). A forked child also records a weak self-reference in its existing child list. A posted signal emit locks and captures that reference, retaining engine operation children until the emit has executed.

Eager-cancel safety: if the parent is already cancelled at the time of fork(), the new child is constructed with its polling flag pre-set (is_cancelled() == true). When the caller subsequently bind_executor s the child, the eager- emit branch in bind_executor fires the child's signal on its first co_await checkpoint. This closes the v0.3.2 "emit-vs-bind race" without an explicit short-circuit at every consumer site.

Pass-by-value into a coroutine frame is fine — shared_ptr copy is cheap and the parent reference inside the child stays valid via shared ownership of the parent. (PR 2 trap shape does NOT apply.)

Definition at line 298 of file cancel.h.

◆ slot()

asio::cancellation_slot neograph::graph::CancelToken::slot ( )
inlinenoexcept

Cancellation slot for binding to a coroutine via asio::bind_cancellation_slot at co_spawn.

asio propagates the cancel through nested co_awaits down to socket operations.

Slots are not thread-safe; this is consumed once by the spawn site, then never read again by user code.

Definition at line 252 of file cancel.h.

◆ throw_if_cancelled()

void neograph::graph::CancelToken::throw_if_cancelled ( const std::string &  detail = {}) const
inline

Throws CancelledException if cancelled.

Convenience wrapper used at engine super-step boundaries.

Definition at line 260 of file cancel.h.

◆ unbind_executor()

void neograph::graph::CancelToken::unbind_executor ( )
inlinenoexcept

Detach the serial executor after every bound operation drained.

This does not drain slot-bound operations. The caller must first ensure that no signal handler or slot-bound operation remains active, then call it before destroying the executor's execution context. As with slot connection, rebinding must not race this teardown.

It serializes with cancel() and posted emits: detachment closes emit admission and waits for an in-progress emit to finish, while queued work from the old binding cannot emit into this or a later binding. Callers must still drain queued work before context teardown and keep directly constructed tokens alive until that drain.

Destroys the last installed slot handler while its context is alive. A completed co_spawn may leave that handler installed, retaining its strand independently of the executor stored in this token.

GraphEngine and the synchronous bridges call this on their internal operation children. Direct callers of bind_executor() must do the same after draining their executor when they retain the token longer than that executor.

Definition at line 227 of file cancel.h.


The documentation for this class was generated from the following file: