- Building Workflows
- Function Registration History
Function Registration History
Every function update, status change, rollback, and deletion is recorded as an immutable entity event on the ironflow:fn:{id} stream. This gives you a full audit trail of configuration changes with per-version snapshots, actor attribution, and change reasons.
Configuration history is not executable history
Section titled “Configuration history is not executable history”Snapshots store function configuration, not handler source or build artifacts. Registration compares configuration and skips an unchanged registration, so a code-only redeploy can retain the version. Rollback restores settings as a new history entry; it does not restore handler code or migrate persisted step results. Event upcasters apply to event schemas, not those results.
A run records the function’s history entity version at creation. Pull worker capabilities derive their version from the live function record, and push dispatch resolves live configuration. Neither mechanism guarantees an immutable executable for a run. See workflow deployment precautions for the version distinctions, compatibility risks, and current safe deployment choices.
Write Flows
Section titled “Write Flows”Register / Update Function
Section titled “Register / Update Function”Client │ │ RegisterFunction(id, config, change_reason) ▼Handler.RegisterFunction │ ├─[new]──► store.CreateFunction(fn, snapshot) ← single transaction │ ├─ INSERT INTO functions (version=1) │ └─ INSERT INTO events │ entity_id = "ironflow:fn:{id}" │ entity_type = "function" │ entity_version = 1 │ name = "FunctionCreated" │ data = { snapshot of initial config, change_type = "created" } │ └─[update]─► snapshot post-update config (state AT new version) │ ▼ store.UpdateFunction(fn, snapshot) ← single transaction │ ├─ SELECT MAX(entity_version) │ FROM events │ WHERE entity_id = "ironflow:fn:{id}" │ ├─ INSERT INTO events │ entity_id = "ironflow:fn:{id}" │ entity_type = "function" │ entity_version = prev + 1 │ name = "FunctionUpdated" │ data = { snapshot of new config } │ └─ UPDATE functions SET ... WHERE id = ? │ ▼ engine.NotifyFunctionUpdated(ctx, fn) engine.SyncFunction(ctx, fn)Update Function Status
Section titled “Update Function Status”Same transactional path as a config update, with change_type = "status_change".
Delete Function
Section titled “Delete Function”DeleteFunction(id) │ ├─ 1. GetFunction(id) ← capture final state │ ├─ 2. store.UpdateFunction(fn, snapshot) │ name = "FunctionDeleted" │ change_type = "delete" │ └─► entity event persists after row is gone │ └─ 3. store.DeleteFunction(id) ← row deleted, event survivesThe deletion snapshot is written before the row is removed so the final configuration remains queryable through ListFunctionHistory even after the function no longer exists.
Read Flows
Section titled “Read Flows”List Function History
Section titled “List Function History”ListFunctionHistory(fn_id, limit, from_version) │ ▼store.ListEntityEvents( entity_id = "ironflow:fn:{fn_id}", direction = "backward", ← newest first BeforeVersion = from_version, ← exclusive backward cursor (proto field `from_version` maps here) limit = limit + 1 ← +1 to detect has_more) │ ▼events table rows │ └─► for each row: json.Unmarshal(data) → FunctionConfigSnapshot │ ▼[]FunctionHistoryEntry { entity_version, snapshot, actor_id, change_reason, change_type }
has_more = len(results) > limitEntries are returned newest-first. The proto field from_version maps to opts.BeforeVersion (an exclusive backward cursor). Pass the lowest entity_version from the previous page to fetch the next.
Get Function at Version
Section titled “Get Function at Version”GetFunctionAtVersion(fn_id, version) │ ▼store.ListEntityEvents( entity_id = "ironflow:fn:{fn_id}", FromVersion = version, ← point lookup at this exact version limit = 1, direction = "forward") │ ├─[not found or version mismatch]──► CodeNotFound └─[found]──► FunctionHistoryEntryRollback Flow
Section titled “Rollback Flow”RollbackFunction(fn_id, target_version, change_reason) │ ├─ 1. GetFunction(fn_id) │ currentFn ← current live config │ ├─ 2. GetFunctionAtVersion(target_version) │ snapshot.Function ← old config to restore │ └─ guard: reject if snapshot.Status == archived │ ├─ 3. Reconstruct fn from snapshot │ fn.ID = currentFn.ID │ fn.Version = currentFn.Version + 1 │ fn.EnvironmentID = currentFn.EnvironmentID │ ├─ 4. Build rollback snapshot (state AT new version = restored config) │ { │ Function: fn, ← restored config (state at new version) │ ChangeType: "rollback", │ ChangeReason: "rollback to v{N}" │ } │ ├─ 5. store.UpdateFunctionVersioned(fn, currentFn.Version, snapshot) │ CAS: WHERE id = ? AND version = ? │ ├─[version conflict]──► CodeAborted (retry) │ └─[ok]──► same atomic transaction as write flow │ entity event written, function row updated │ ├─ 6. engine.SyncFunction(ctx, fn) └─ 7. engine.NotifyFunctionUpdated(ctx, fn)Rollback is itself recorded as a new history entry, so the audit trail shows both the intent and the resulting config change.
Data Model
Section titled “Data Model”History events are rows in the shared events table, namespaced under the reserved ironflow: entity ID prefix. User-defined entity streams cannot use this prefix.
events table┌──────────────────┬──────────────┬────────────────┬──────────────────────┐│ entity_id │ entity_type │ entity_version │ name │├──────────────────┼──────────────┼────────────────┼──────────────────────┤│ ironflow:fn:abc │ function │ 1 │ FunctionCreated ││ ironflow:fn:abc │ function │ 2 │ FunctionUpdated ││ ironflow:fn:abc │ function │ 3 │ FunctionDeleted ││ user:order:xyz │ order │ 1 │ OrderPlaced │ ← user stream└──────────────────┴──────────────┴────────────────┴──────────────────────┘Each data column is a FunctionConfigSnapshot JSON blob containing:
| Field | Description |
|---|---|
function | Full function config as of this version (state AT this entity_version, not before it) |
actor_id | API key or user that triggered the change |
change_reason | Optional free-text label (e.g. "deploy v2.1.0") |
change_type | created | update | status_change | rollback | delete |
snapshot_version | 0 (absent) = legacy pre-change semantics; 1 = current post-change semantics |
API Reference
Section titled “API Reference”| RPC | Description |
|---|---|
RegisterFunction | Pass change_reason to annotate the history entry |
ListFunctionHistory | Paginated history, newest-first, keyset via from_version (maps to BeforeVersion). limit defaults to 50, capped at 200. |
GetFunctionAtVersion | Fetch snapshot at a specific entity_version |
RollbackFunction | Restore a prior version; recorded as a rollback entry |