AgentStack
SKILL verified Apache-2.0 Self-run

Resonate Recursive Fan Out Pattern Go

skill-resonatehq-resonate-skills-resonate-recursive-fan-out-pattern-go · by resonatehq

Implement recursive fan-out / parallel workflow execution in Go with Resonate — dispatch all children via ctx.RPC or ctx.Run, collect futures in a slice, then await each. Use when processing batches, trees, or graphs where each child is independently durable and optionally recurses. Pre-release caveat: the Go SDK has no semver tag yet; pin a commit for stability.

No reviews yet
0 installs
11 views
0.0% view→install

Install

$ agentstack add skill-resonatehq-resonate-skills-resonate-recursive-fan-out-pattern-go

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Resonate Recursive Fan Out Pattern Go? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Resonate Recursive Fan-Out Pattern — Go

> Pre-release caveat. The Go SDK has no semver-tagged release yet — go get …@latest resolves to a pseudo-version; pin a commit for stability. APIs may change before the first tag is cut. Every code block here is verified against develop/go.mdx and the example-fan-out-fan-in-go / example-recursive-factorial-go repos at SDK commit 22076134651f.

Overview

Recursive fan-out dispatches multiple child invocations in parallel, awaits them individually, and optionally recurses deeper. The Go expression is a two-loop pattern: a dispatch loop builds a []*resonate.Future slice, then a separate await loop reads each result. Mixing dispatch and await serializes the children — that is the single most common mistake.

For the language-agnostic mental model (promise deduplication, load-balancing, detached vs. result-gathering), see resonate-recursive-fan-out-pattern-typescript.

When to use

  • Batch processing where items are independent and each needs durability
  • Map-reduce shaped workflows (fan out N workers, aggregate results)
  • Recursive tree / graph traversal with dynamic depth
  • Any case where a crash mid-fan-out must resume, not restart from zero

Dispatch-then-await shape

The canonical fan-out from example-fan-out-fan-in-go — dispatch all children first, await all second:

type FanoutArgs struct {
    Channels []string `json:"channels"`
    Message  string   `json:"message"`
}

type FanoutResult struct {
    Delivered []Delivery `json:"delivered"`
}

type SendArgs struct {
    Channel string `json:"channel"`
    Message string `json:"message"`
}

type Delivery struct {
    Channel string `json:"channel"`
    OK      bool   `json:"ok"`
    Reason  string `json:"reason,omitempty"`
}

func fanout(ctx *resonate.Context, args FanoutArgs) (FanoutResult, error) {
    // Dispatch loop — create all durable promises before awaiting any.
    futures := make([]*resonate.Future, 0, len(args.Channels))
    for _, ch := range args.Channels {
        f, err := ctx.RPC("send", SendArgs{Channel: ch, Message: args.Message})
        if err != nil {
            return FanoutResult{}, err
        }
        futures = append(futures, f)
    }

    // Await loop — read results in order; record per-child failures.
    out := FanoutResult{Delivered: make([]Delivery, 0, len(futures))}
    for i, f := range futures {
        var d Delivery
        if err := f.Await(&d); err != nil {
            out.Delivered = append(out.Delivered, Delivery{
                Channel: args.Channels[i],
                OK:      false,
                Reason:  err.Error(),
            })
            continue
        }
        out.Delivered = append(out.Delivered, d)
    }
    return out, nil
}

The dispatch loop runs serially in Go code, but each ctx.RPC creates an independent durable promise on the server — all children execute concurrently. The await loop only reads results; it does not gate execution of siblings.

Recursive fan-out

A workflow can call ctx.RPC(SameName, smallerArgs) to recurse. Each recursive call is its own durable promise; with multiple workers running the same registered name, the promise tree fans out across them automatically. From example-recursive-factorial-go:

// factorial/factorial.go

const Name = "Factorial"
const WorkerGroup = "factorial-workers"

type Args struct {
    N int `json:"n"`
}

func Workflow(ctx *resonate.Context, args Args) (int, error) {
    // Base case — must always be present to terminate the recursion.
    if args.N ` sibling

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [resonatehq](https://github.com/resonatehq)
- **Source:** [resonatehq/resonate-skills](https://github.com/resonatehq/resonate-skills)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.