Documentation
¶
Overview ¶
Package exportasync runs a long export in the background and lets its caller read it again by its idempotency key (#2212).
graphql_export and api_export walk every page inside one tool call. A walk longer than the model client's own tool-call timeout failed on the client's side, with no asset written and no handle to reconnect to, and a client does not let the platform raise that timeout. An export asked to run in the background (async, or a page walk from a model client) is answered at once with a run id and an idempotency key; the walk runs on the replica that took the call. Calling the same export again with the key reads the run: its progress while it runs, the export's own answer once it is done, and its failure if it failed. A key whose export is still running answers with that run, so a retry never starts a second walk against the upstream.
A run is a call task (internal/platform/calltask), the record the MCP Tasks extension keeps, marked as a background export; the Tasks extension is for a client that declares it, and this is the same work for one that does not.
Index ¶
- Constants
- Variables
- func Begin(ctx context.Context, b Background, ...) *mcp.CallToolResult
- func HowToReadAgain(tool, key string) string
- func NewKey() (string, error)
- func Report(ctx context.Context, pages, items int)
- func Result(run *Run) (*mcp.CallToolResult, error)
- func Start(ctx context.Context, l Launch, ...) *mcp.CallToolResult
- func Wanted(runner Runner, async *bool, walk, modelClient bool) bool
- func WithProgress(ctx context.Context, cell *Cell) context.Context
- type Answer
- type Background
- type Cell
- type Launch
- type Progress
- type Run
- type Runner
Constants ¶
const ( StatusRunning = "running" StatusCompleted = "completed" StatusFailed = "failed" )
The states a run is in.
Variables ¶
var ErrNotFound = errors.New("no background export under this idempotency key")
ErrNotFound is a key no run of the caller's has.
Functions ¶
func Begin ¶
func Begin(ctx context.Context, b Background, work func(ctx context.Context) (*mcp.CallToolResult, error)) *mcp.CallToolResult
Begin starts work as a background export under b.Key, or joins the one already running under it, and answers the caller with the run.
func HowToReadAgain ¶
HowToReadAgain is the sentence a call naming a key is told how to read its run with.
func NewKey ¶
NewKey mints the idempotency key a background export the caller named none for is read again by.
func Report ¶
Report records how far the export running on ctx has come. A context that carries no cell, an export answered inline, records nothing.
func Result ¶
func Result(run *Run) (*mcp.CallToolResult, error)
Result decodes a completed run's answer back into the tool result it was.
func Start ¶
func Start(ctx context.Context, l Launch, work func(ctx context.Context) (*mcp.CallToolResult, error)) *mcp.CallToolResult
Start fills in the launch's key and timeout and begins work in the background, answering with the run.
Types ¶
type Answer ¶
type Answer struct {
RunID string `json:"run_id"`
Status string `json:"status"`
IdempotencyKey string `json:"idempotency_key"`
PagesFetched int `json:"pages_fetched"`
ItemsMerged int `json:"items_merged"`
// StartedAt and UpdatedAt are when the run started and last reported.
StartedAt time.Time `json:"started_at"`
UpdatedAt time.Time `json:"updated_at"`
Message string `json:"message"`
}
Answer is what a background export's caller is handed, at the start and on every read of a run not yet completed.
type Background ¶
type Background struct {
Runner Runner
Tool string
Key string
// How is the sentence telling the caller how to read the run again.
How string
// Prior is a failed run Resume found under the key, which the answer
// names.
Prior *Run
}
Background is one export to start in the background.
type Cell ¶
type Cell struct {
// contains filtered or unexported fields
}
Cell is where a running export writes its progress for the runner to read.
type Launch ¶
type Launch struct {
Runner Runner
Tool string
Prior *Run
// Key is the call's idempotency_key, minted when it names none. Pointing
// it at the argument the export writes its asset under means a call
// naming the key after the run is gone still finds the asset.
Key *string
// Timeout is the call's timeout_seconds, set to MaxTimeout when it names
// none: nobody is waiting on the call.
Timeout *int
MaxTimeout time.Duration
}
Launch is one export a tool starts in the background: the fields of its own arguments the launch fills in, and how the deployment bounds it.
type Progress ¶
type Progress struct {
PagesFetched int `json:"pages_fetched"`
ItemsMerged int `json:"items_merged"`
}
Progress is how far a walk has come.
type Run ¶
type Run struct {
ID string
Status string
// Message is the run's own sentence: what it is doing, or why it failed.
Message string
Progress Progress
// Result is the export's answer once it completed, in the wire form a
// tool result takes.
Result json.RawMessage
StartedAt time.Time
UpdatedAt time.Time
}
Run is one background export as its caller reads it.
func Resume ¶
func Resume(ctx context.Context, runner Runner, tool, key, how string) (res *mcp.CallToolResult, prior *Run, handled bool)
Resume answers a call that names the idempotency key of one of its caller's background exports: with the run's progress while it runs, and with the export's own answer once it completed. A run that failed is returned as prior with handled false, and the call goes on to run the export again; the new run's answer names the failure. A key no background export has, and a deployment with no runner, are not handled.
type Runner ¶
type Runner interface {
// Start runs work apart from the request under key, or answers with the
// run already working under it for this caller and tool, with started
// false.
Start(ctx context.Context, tool, key string, work func(ctx context.Context) (*mcp.CallToolResult, error)) (run *Run, started bool, err error)
// Find reads the latest run of tool under key for the caller, or
// ErrNotFound.
Find(ctx context.Context, tool, key string) (*Run, error)
}
Runner starts background exports and finds them again. The caller is read from ctx: a run is found only by the person who started it.