-
-
Notifications
You must be signed in to change notification settings - Fork 1
601. Tips & tricks
F-Mesh is configured at construction time via functional options on fmesh.New. See also Scheduling rules for how config affects execution.
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")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 |
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)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.
The default 5-second time limit and 1000-cycle limit can cause unexpected termination:
fm, err := fmesh.New("long-running",
fmesh.WithUnlimitedCycles(),
fmesh.WithUnlimitedTime(),
)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
)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.
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
}Instead of wrapping payloads in signal.New, use PutPayloads:
_ = c.InputByName("i1").PutPayloads("hello", "world")Use built-in signal predicates instead of inline closures when possible:
highPriority := port.Signals().Filter(signal.LabelEquals("priority", "high"))For higher-level techniques — topologies, feedback loops, tick-driven simulations, observing a running mesh — see Patterns & recipes.