Skip to content
github-actions[bot] edited this page Jul 23, 2026 · 3 revisions

Mesh configuration

F-Mesh is configured at construction time via functional options on fmesh.New. See also Scheduling rules for how config affects execution.

Config struct

type Config struct {
    ErrorHandlingStrategy ErrorHandlingStrategy
    Debug                 bool
    CyclesLimit           int           // 0 = unlimited
    TimeLimit             time.Duration // 0 = unlimited
    CyclesHistoryLimit    int           // 0 = unlimited — how many past cycles RuntimeInfo keeps
}

Defaults: StopOnFirstErrorOrPanic, 1000 cycles, 5 second time limit, unlimited cycles history, debug off.

fm, err := fmesh.New("simple mesh")

Configuration options

fm, err := fmesh.New("simple mesh",
    fmesh.WithErrorHandlingStrategy(fmesh.IgnoreAll),
    fmesh.WithCyclesLimit(100),
    fmesh.WithTimeLimit(30 * time.Second),
    fmesh.WithUnlimitedCycles(),
    fmesh.WithUnlimitedTime(),
    fmesh.WithCyclesHistoryLimit(10),
    fmesh.WithUnlimitedCyclesHistory(),
    fmesh.WithDebug(true),
    fmesh.WithLogger(myLogger),
    fmesh.WithLabel("env", "production"),
    fmesh.WithScalar("version", 2.0),
)

Or replace the entire config:

fm, err := fmesh.New("simple mesh", fmesh.WithConfig(fmesh.Config{
    ErrorHandlingStrategy: fmesh.IgnoreAll,
    CyclesLimit:           0,
    TimeLimit:             0,
    Debug:                 true,
}))
Option Description
WithConfig Replace entire Config
WithErrorHandlingStrategy StopOnFirstErrorOrPanic, StopOnFirstPanic, or IgnoreAll
WithCyclesLimit Max cycles (must be > 0)
WithUnlimitedCycles Remove cycle limit
WithTimeLimit Max duration (must be > 0)
WithUnlimitedTime Remove time limit
WithCyclesHistoryLimit Keep only the N most recent cycles in RuntimeInfo.Cycles (must be > 0; bounds memory on long runs)
WithUnlimitedCyclesHistory Remove the history limit (the default)
WithDebug Log per-component activation results each cycle
WithLogger Logger inherited by components without their own
WithLabel / WithScalar Set mesh metadata at construction

FMesh identity and metadata

Beyond config, FMesh exposes:

fm.Name()         // mesh name (set at construction)
fm.Description()  // set via the fmesh.WithDescription("ETL pipeline") option

// Labels (mutating API — same as components/ports)
fm.AddLabel("env", "prod")
fm.SetLabels(map[string]string{"team": "data"})
fm.Labels().ValueOrDefault("env", "dev")

// Scalars
fm.AddScalar("priority", 1.0)
fm.Scalars().ValueOrDefault("priority", 0)

Logging

When WithDebug(true) is set, the mesh logs activation results each cycle via LogDebug. Access the logger at runtime:

fm.Logger()
fm.IsDebug()

Components without an explicit logger inherit fm.Logger() when added via AddComponents.

Removing default limits

The default 5-second time limit and 1000-cycle limit can cause unexpected termination:

fm, err := fmesh.New("long-running",
    fmesh.WithUnlimitedCycles(),
    fmesh.WithUnlimitedTime(),
)

Bounding memory on long runs

RuntimeInfo.Cycles keeps the full cycle history by default, and it grows for the whole run. For meshes that execute many cycles, cap it with a sliding window — the engine itself only needs the last cycle; older ones exist for observability:

fm, err := fmesh.New("long-running",
    fmesh.WithUnlimitedCycles(),
    fmesh.WithUnlimitedTime(),
    fmesh.WithCyclesHistoryLimit(10), // keep only the 10 most recent cycles
)

Signal immutability

Signals are copy-on-write. When a signal is fanned out to multiple ports, all destinations share the same pointer. Always use WithLabel, WithLabels, MapPayload, etc. to produce modified copies rather than mutating shared state.

Nil-safe lookups

Methods like ComponentByName, InputByName, and OutputByName return nil when the entity is not found. Always check for nil:

if port := c.InputByName("data"); port != nil {
    // use port
}

PutPayloads shortcut

Instead of wrapping payloads in signal.New, use PutPayloads:

_ = c.InputByName("i1").PutPayloads("hello", "world")

Predicate helpers for filtering

Use built-in signal predicates instead of inline closures when possible:

highPriority := port.Signals().Filter(signal.LabelEquals("priority", "high"))

Clone this wiki locally