Skip to content

Releases: Tochemey/goakt

v4.2.0

31 Mar 08:34
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

What's Changed

✨ Features

  • log: Add NewSlogFrom to create a Logger from an existing *slog.Logger (#1133)
  • Add CRDT capabilities (#1135). More info can be found in the doc
  • Add data center–aware CRDT features (#1139)

🐛 Fixes

  • Fix context propagation for grain and broken tests (#1137)

🔧 Refactoring

  • Refactor distributed data (ddata) implementation (#1138)

Full Changelog: v4.1.1...v4.2.0 and https://github.com/Tochemey/goakt/blob/main/CHANGELOG.md#v420---2026-03-31

v4.1.1

27 Mar 21:17
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

✨ New Additions

🌊 stream Package — Reactive Streams for GoAkt

A new top-level stream package brings demand-driven, actor-native stream processing to GoAkt.
Every pipeline stage runs inside a GoAkt actor, inheriting supervision, lifecycle management, and
location transparency automatically. Pipelines are lazy: nothing executes until RunnableGraph.Run
is called against a live ActorSystem.

🧩 Core Abstractions

Abstraction Description
Source[T] Lazy description of a stream origin; assembled with Via / To into a RunnableGraph
Flow[In, Out] Lazy description of a transformation stage; type-safe, composable
Sink[T] Lazy description of a terminal consumer stage
RunnableGraph Fully assembled pipeline; a value type that can be Run multiple times for independent instances
StreamHandle Live handle returned by Run; exposes ID(), Done(), Err(), Stop(ctx), Abort(), and Metrics()

📥 Sources

Constructor Description
Of[T](values...) 📋 Finite source from a fixed set of values
Range(start, end) 🔢 Integer range source ([start, end))
FromChannel[T](ch) 📡 Reads from a Go channel; completes when the channel closes
FromActor[T](pid) 🤖 Pulls from a GoAkt actor using the PullRequest / PullResponse[T] protocol
Tick(interval) ⏱️ Emits time.Time on a fixed interval; runs until cancelled
Merge[T](sources...) 🔀 Fans N sources into one; completes when all inputs complete
Combine[T,U,V](left, right, fn) 🤝 Zips two sources pairwise via fn; zip semantics
Broadcast[T](src, n) 📢 Fans one source out to N independent branches
Balance[T](src, n) ⚖️ Distributes one source across N branches (round-robin with backpressure)
FromConn(conn, bufSize) 🌐 Reads []byte frames from a net.Conn
Unfold[S,T](seed, step) 🌱 Generates values from a seed with a stateful step function

🔄 Flows

Constructor Description
Map[In,Out](fn) 🗺️ Type-changing transformation; no error path
TryMap[In,Out](fn) 🛡️ Transformation with error; ErrorStrategy controls failure handling
Filter[T](predicate) 🔍 Keeps only elements where predicate returns true
FlatMap[In,Out](fn) 📤 Expands each element into a slice of outputs
Flatten[T]() 📦 Unwraps []T elements into individual elements
Batch[T](n, maxWait) 📦 Groups elements into []T slices of at most n; flushes early after maxWait
Buffer[T](size, strategy) 💾 Asynchronous buffer with configurable overflow strategy
Throttle[T](n, per) 🚦 Limits throughput to at most n elements per per duration
Deduplicate[T]() 🔁 Suppresses consecutive duplicate elements (T must be comparable)
Scan[In,State](zero, fn) 📊 Running accumulation; emits each intermediate state
WithContext[T](key, value) 🏷️ Labels a tracing boundary; passes elements through unchanged
ParallelMap[In,Out](n, fn) ⚡ Applies fn concurrently with up to n goroutines; unordered output
OrderedParallelMap[In,Out](n, fn) 📐 Like ParallelMap but preserves input order (min-heap resequencing)

📤 Sinks

Constructor Description
ForEach[T](fn) 🔄 Calls fn for each element
Collect[T]() 📋 Accumulates all elements; retrieve via Collector[T].Items() after completion
Fold[T,U](zero, fn) ➕ Reduces to a single value; retrieve via FoldResult[U].Value()
First[T]() 🥇 Captures the first element then cancels upstream
Ignore[T]() 🗑️ Discards all elements; useful for side-effecting flows
Chan[T](ch) 📡 Writes each element to a Go channel; applies natural backpressure when full
ToActor[T](pid) 🤖 Forwards each element to a GoAkt actor via Tell
ToActorNamed[T](system, name) 🏷️ Resolves actor by name on each element and forwards via Tell

🏗️ Pipeline DSL

  • From[T](src) — starts a LinearGraph[T] fluent builder
  • LinearGraph[T].Via(flow) — chains a type-preserving flow
  • LinearGraph[T].To(sink) — attaches a sink and returns a RunnableGraph
  • ViaLinear[In,Out](g, flow) — type-changing step on a LinearGraph
  • Via[In,Out](src, flow) — package-level free function for type-changing flows on Source
  • Graph DSL — named-node builder for non-linear topologies (fan-out, fan-in, merge)

🔙 Backpressure & Configuration

  • Credit-based demand propagation: sinks signal demand upstream; sources produce only what is requested
  • StageConfig — per-stage knobs: InitialDemand, RefillThreshold, ErrorStrategy, RetryConfig, OverflowStrategy, BufferSize, Mailbox, Name, Tags, Tracer, Fusion, MicroBatch, PullTimeout, OnDrop
  • ErrorStrategyFailFast (default), Resume (skip), Retry (with RetryConfig.MaxAttempts), Supervise
  • OverflowStrategyDropTail, DropHead, DropBuffer, Backpressure, Fail
  • FusionModeFuseStateless (default, fuses adjacent Map/Filter stages into one actor), FuseNone, FuseAggressive

🔭 Observability

  • Tracer interface — per-element hooks: OnElement, OnDemand, OnError, OnComplete; attach via WithTracer
  • MetricsReporter interface — snapshot forwarding to external systems (Prometheus, OTel)
  • StreamHandle.Metrics() — live StreamMetrics snapshot with element-in, element-out, and error counts

⚡ Performance Internals

  • 🕐 time.Now() guarded by tracer != nil on the element hot path — no clock overhead when tracing is disabled
  • 📦 fusedFlowActor (stage-fusion fast path) uses credit-based batch demand refill instead of one streamRequest allocation per element, reducing demand-message overhead by ~160x under default configuration
  • 📡 chanSourceActor bridges external channels to the actor mailbox in batches of up to 64 values per actor.Tell call (drain-without-blocking strategy), significantly reducing mailbox-enqueue overhead on high-throughput channels
  • 🏊 connSourceActor pools full-sized read buffers via sync.Pool; each element sent downstream is an exact-sized copy, eliminating a per-read heap allocation
  • 🗑️ Filter and Deduplicate return nil instead of an empty []any{} for skipped elements, removing a slice allocation on every filtered-out element
  • 🔢 Stream sub-IDs use an atomic counter instead of UUID generation, avoiding an entropy read and string-formatting cost on every RunnableGraph.Run call
  • 🐛 flowActor.tryFlushOutput now fires Tracer.OnElement with the definitively-assigned sequence number, fixing incorrect seqNo reporting for multi-output transforms (FlatMap)

🔀 Pull Request

  • chore(deps): update module golang.org/x/net to v0.52.0 by @renovate[bot] in #1124
  • chore(deps): update actions/upload-artifact action to v7 by @renovate[bot] in #1125
  • feat: add streaming capabilities by @Tochemey in #1126
  • chore(deps): update dependency go to v1.26.1 by @renovate[bot] in #1127
  • chore(deps): update golang docker tag to v1.26.1 by @renovate[bot] in #1128
  • chore(deps): update module github.com/bufbuild/buf to v1.66.1 by @renovate[bot] in #1129
  • chore(deps): update dependency golangci/golangci-lint to v2.11.3 by @renovate[bot] in #1130

Full Changelog: v4.1.0...v4.1.1 and https://github.com/Tochemey/goakt/blob/main/changelog.md#v411---2026-03-27

v4.1.0

16 Mar 08:44
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

What Changed

⚠️ Breaking Changes

This release refines the actor identity model introduced in v4.0.0 by propagating the Path interface through all lifecycle and dead-letter event types, replacing raw string addresses throughout the event API.

Lifecycle & Dead-Letter Events Now Use Path

The following types have been updated:

Type Old New
Deadletter Sender() string, Receiver() string Sender() Path, Receiver() Path
Terminated Address() string ActorPath() Path
ActorStarted Address() string ActorPath() Path
ActorStopped Address() string ActorPath() Path
ActorPassivated Address() string ActorPath() Path
ActorChildCreated Address() string, Parent() string ActorPath() Path, Parent() Path
ActorRestarted Address() string ActorPath() Path
ActorSuspended Address() string ActorPath() Path
ActorReinstated Address() string ActorPath() Path

Migration Guide

  1. Replace .Address() calls on event types with .ActorPath()
// Before
handler := func(evt *actor.ActorStarted) {
    fmt.Println(evt.Address()) // string
}

// After
handler := func(evt *actor.ActorStarted) {
    fmt.Println(evt.ActorPath().String()) // Path
}

This is a focused follow-up to v4.0.0's Path interface introduction, completing the migration of event types to the unified identity model. No new features or bug fixes are included in this release.

Pull Requests

  • chore: code maintenance by @Tochemey in #1117
  • chore(deps): update go minor and patch by @renovate[bot] in #1119
  • chore(deps): update module github.com/bufbuild/buf to v1.66.0 by @renovate[bot] in #1120
  • chore: upgrade dependencies by @Tochemey in #1121
  • chore(deps): update dependency golangci/golangci-lint to v2.10.1 by @renovate[bot] in #1118
  • refactor: 💥 use Path type in dead letters and terminated messages by @Tochemey in #1122

Full Changelog: v4.0.0...v4.1.0

v4.0.0

05 Mar 22:22
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

GoAkt v4.0.0

Production-ready release — Unified APIs, typed messages with any, pluggable serializers, and config-only remoting.

Installation

go get github.com/tochemey/goakt/v4

What's New

v4.0.0 delivers simplification and performance across the board:

  • *PID — Sole actor reference for both local and remote actors; ActorRef removed
  • ActorOf(ctx, name) — Unified lookup replacing LocalActor and RemoteActor; returns a local or remote PID
  • Actors(ctx, timeout) — Replaces both Actors() and ActorRefs(); returns ([]*PID, error)
  • any messagesproto.Message constraint removed from all public APIs (Tell, Ask, Schedule*, AskGrain, TellGrain)
  • Pluggable serializers — ProtoSerializer (default) for protobuf; CBORSerializer for arbitrary Go types with automatic type registration
  • Path interface — Location-transparent actor identity via pid.Path(); address package moved to internal/address
  • Config-only remoting — Remoting client is internal; configure via WithRemote(config) on the actor system
  • Consistent Hash Router — New routing strategy for partition-affinity and sticky-session use cases
  • Extended Logger — Context-aware and introspection methods added; slog and Zap implementations included

Breaking Changes

Key migrations at a glance:

From To
proto.Message in handlers / call sites any
ActorRef *PID
ActorOf(addr, pid, err) ActorOf(*PID, error)
LocalActor(name) / RemoteActor(ctx, name) ActorOf(ctx, name)
Actors() + ActorRefs(ctx, timeout) Actors(ctx, timeout) ([]*PID, error)
RemoteScheduleOnce / RemoteSchedule / RemoteScheduleWithCron Schedule* with remote PID from ActorOf
pid.Address() pid.Path()
ctx.SenderAddress() / ctx.ReceiverAddress() ctx.Sender().Path() / ctx.Self().Path()
testkit.Probe.SenderAddress() Sender() + pid.Path()
goaktpb.* actor.* (e.g. actor.PostStart, actor.PoisonPill)
WithRemoting WithRemote(config) (actor system) / WithRemoteConfig(config) (client node)
Custom Logger implementations Must implement new context-aware and introspection methods

Full migration guide: CHANGELOG_V400.md

Bug Fixes

  • Fixed stale kind entries causing ErrKindAlreadyExists / ErrSingletonAlreadyExists on new leader election. cleanupCluster now checks pid.singletonSpec != nil instead of pid.IsSingleton(), which was incorrectly returning false after pid.reset() cleared the singleton state during shutdown.

Resources

Pull Requests

  • docs: add architecture documentation by @Tochemey in #1101
  • feat: replace proto.Message with any and allow custom remote serialization by @Tochemey in #1102
  • refactor: remove unnecessary methods on receive context by @Tochemey in #1103
  • refactor: move remote client to internal and refactor spawn by @Tochemey in #1105
  • refactor: enhance the PID implementation and remote calls by @Tochemey in #1106
  • feat: ✨ v400: additional refactoring and api changes by @Tochemey in #1107
  • feat(v400): ✨ add the selfmanaged discovery provider by @Tochemey in #1108
  • docs(v400): add an logo and icon images by @Tochemey in #1109
  • fix(v400): fix ask and tell using the api to handle remote PID by @Tochemey in #1110
  • feat(v400): set the default cbor serializer by @Tochemey in #1111
  • perf: add proactive cluster sync on node join by @Tochemey in #1113
  • chore(deps): update dependency golangci/golangci-lint to v2.10.1 by @renovate[bot] in #1112
  • refactor: handle context propagation omitted remote handlers by @Tochemey in #1114
  • feat: add consistent hash router by @Tochemey in #1115

Full Changelog: v3.14.0...v4.0.0 and https://github.com/Tochemey/goakt/blob/main/changelog.md#v400---2026-03-05

v3.14.0

18 Feb 19:59
Immutable release. Only release title and notes can be modified.
3d02f49

Choose a tag to compare

🚀 Oveview

This release brings multi-datacenter support, a high-performance protobuf-over-TCP remoting stack, and important fixes for channel pooling, timeouts, and data races. It also adds an option to disable grain relocation and several allocation and lock optimizations across the hot paths.

✨ What's New

🌐 Multi-datacenter support

  • DC-transparent messaging — actors and grains can communicate across datacenters without changing your code.
  • Pluggable control plane — use NATS JetStream or Etcd for coordination.
  • DC-aware placement — spawn actors in a specific datacenter with SpawnOn and the WithDataCenter option.
  • See the datacenter package and WithDataCenter for details.

🛡️ Grain relocation control

  • WithGrainDisableRelocation — disable actor/grain relocation when you don’t need it (e.g. stateless actors or short-lived grains).

🐛 Bug Fixes

Area Fix
Shutdown preShutdown no longer builds or persists peer state when relocation is disabled (WithoutRelocation), so shutdown proceeds correctly and avoids unnecessary cluster work.
Channel pool Fixed channel-pool poisoning in GrainContext.NoErr(): sending on both response and error channels for sync calls could corrupt the pool under scheduling races.
Timeouts Fixed localSend timeout/cancel paths returning channels to the pool while the grain goroutine could still write, preventing stale values in later requests.
Data race Fixed race in PID.recordProcessedMessage() by replacing the runtime type assertion on passivationStrategy with an atomic.Bool set at init.

⚡ Performance & Remoting

🌐 New remoting stack (protobuf over TCP)

ConnectRPC/HTTP-based remoting is replaced with a protobuf-over-TCP server and connection-pooling client:

  • Multi-loop TCP accept with SO_REUSEPORT, TCP_FASTOPEN, and TCP_DEFER_ACCEPT for lower connection-setup latency and kernel-level load balancing.
  • Sharded WorkerPool for connection dispatch, reducing contention under high concurrency.
  • Length-prefixed wire protocol with dynamic protobuf type dispatch via the global registry (no per-service stubs or HTTP path routing).
  • FramePool with power-of-two bucketed sync.Pool (256 B – 4 MiB) for read buffers and frame slices to cut heap allocations and GC pressure.
  • LIFO connection pool in the TCP client with lazy stale-connection eviction and no background goroutines.
  • Pluggable ConnWrapper compression (Zstandard, Brotli, Gzip) on both client and server.

♻️ Pooling & allocation

  • Bounded channel-based pools instead of sync.Pool for ReceiveContext, GrainContext, and response/error channels on the Tell, Ask, SendAsync, and SendSync hot paths to avoid cross-P thrashing and madvise overhead.
  • PID.latestReceiveTimeNano switched from atomic.Time to atomic.Int64 (Unix nanoseconds) to remove ~24-byte interface allocations per message.
  • Cached Address.String() and GrainIdentity.String() to avoid repeated fmt.Sprintf on every message.
  • Mailbox nodes in UnboundedMailbox and grainMailbox use plain pointers instead of atomic.Pointer on enqueue/dequeue.
  • Inlined defer closures in Ask-path functions (PID.Ask, actor.Ask, handleRemoteAsk, grain localSend) to remove per-call closure allocations.

🔓 Locking & contention

  • ActorOf does local actor lookup before taking the system-wide RWMutex; SendAsync/SendSync bypass the PID.ActorSystem() getter lock, reducing read-lock acquisitions from three to one on the local path.
  • passivationManager.Touch coalesced via an atomic timestamp guard (lastPassivationTouch), so mutex contention drops from once-per-message to at most once per 100 ms.

📦 Upgrade notes

  • Remoting now uses the new TCP-based stack by default. No API changes are required for typical usage.
  • Use WithGrainDisableRelocation when you want to skip relocation for certain grains.
  • For multi-DC setups, use the datacenter package and WithDataCenter with SpawnOn.

🔗 Pull requests

Features & refactors

Dependencies & tooling


Full Changelog: v3.13.0...v3.14.0

v3.13.0

23 Jan 14:08
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

🚀 What's Changed

✨ Features

🐛 Bug Fixes

  • fix: enhance robustness of the relocation process by @Tochemey in #1071

⚡ Performance Improvements

  • perf(actor): refactor how node publishes its state before gracefully leaving by @Tochemey in #1079
  • perf: ⚡ refactor default logger to enhance performance by @Tochemey in #1080
  • perf: ⚡ refactor remoting to boost performance by @Tochemey in #1083

🔨 Refactoring

  • refactor: refactor the implementation of the cluster engine by @Tochemey in #1074

🧹 Maintenance & Dependency Updates

  • chore(deps): update Golang Docker tag to v1.25.5 by @renovate[bot] in #1059
  • chore(deps): update module github.com/bufbuild/buf to v1.62.1 by @renovate[bot] in #1075
  • chore(deps): update module github.com/bufbuild/buf to v1.63.0 by @renovate[bot] in #1081

Full Changelog:

v3.12.1

06 Jan 17:30
Immutable release. Only release title and notes can be modified.
d48d69b

Choose a tag to compare

What's Changed

✨ New Features

🛠 Refactors & Maintenance

📚 Documentation

Full Changelog: v3.12.0...v3.12.1 and https://github.com/Tochemey/goakt/blob/main/changelog.md#v3121---2026-06-01

v3.12.0

31 Dec 14:35
Immutable release. Only release title and notes can be modified.
e1c9270

Choose a tag to compare

🚀 Highlights

This release focuses on robustness, resilience, and developer experience, with significant improvements across clustering, grains, scheduling, and maintenance.

✨ New Features

  • ✨ Remoting calls for Grains Enables remote interactions with Grains for distributed workflows. (@Tochemey · #1027)
  • 🧪 Basic TestKit support for Grains Introduces foundational testing utilities to simplify Grain testing. (@Tochemey · #1033)
  • 🧭 Default supervisor configuration SpawnOn now uses the system-wide default supervisor strategy. A new option, WithDefaultSupervisor, has been added to explicitly configure it. (@Tochemey · #1018)

🐛 Bug Fixes

  • Grain activation revamp Prevents panics and duplicate activations during Grain lifecycle handling. (@Tochemey · #1023)
  • Recovery support for Grain de/activation Adds recovery capabilities to improve fault tolerance. (@Tochemey · #1030)
  • Actor count correctness Fixes mismatches as well as underflow and overflow issues in actor counts. (@Tochemey · #1035)
  • Scheduler reliability Fixes an issue where ScheduleOnce() did not always trigger as expected. (@majiayu000 · #1039)

♻️ Refactors & Improvements

  • Address implementation overhaul Revamps address handling and adds support for configuring a default supervisor. (@Tochemey · #1019)
  • Supervisor system overhaul (@Tochemey · #1018)
    • Supervisor logic has been moved into its own dedicated package: supervisor
    • Migrating existing code only requires replacing actor with supervisor Breaking Change
  • Improved relocation semantics (@Tochemey · #1018)
    • Ensures child actors are not relocated unintentionally during relocation
    • Adds support to relocate actors with their configured supervisor strategy
  • Restart behaviour revamp The Restart implementation now restarts the entire child family tree, ensuring consistent recovery semantics. (@Tochemey · #1018)
  • Cluster storage DB file creation Reimplements DB file creation logic for improved reliability. (@Tochemey · #1025)
  • Cluster singleton resilience Makes singleton spawning more robust in clustered environments. (@Tochemey · #1038)
  • Reduced shutdown log noise Avoids unnecessary log spam during actor system shutdown. (@Tochemey · #1032)
  • General code maintenance Internal refactors and cleanup for long-term maintainability. (@Tochemey · #1026)

🧹 Chores & Dependency Updates

  • Cluster engine dependency upgrade Keeps the cluster engine up to date. (@Tochemey · #1041)
  • Dependency maintenance Routine dependency updates and housekeeping. (@Tochemey · #1042)

🙌 New Contributors

Full Changelog: https://github.com/Tochemey/goakt/blob/main/changelog.md

v3.11.2

18 Dec 11:50
Immutable release. Only release title and notes can be modified.
7c44a4a

Choose a tag to compare

🧰 Maintenance

Full Changelog: v3.11.1...v3.11.2

v3.11.1

12 Dec 01:37
Immutable release. Only release title and notes can be modified.
9e5369b

Choose a tag to compare

🚀 Highlights

  • ⚡ Refactor the implementation of Kill method to take into consideration cluster mode.

🔗 Pull Requests

Full Changelog: v3.11.0...v3.11.1