Valkey modules must declare atomic migration support
Valkey 9 RC2 requires modules to opt into atomic slot migration. New lifecycle events and changes to function handling clarify which state belongs to a migrating slot.
Loading a key and owning its cluster slot become different events during atomic slot migration. The destination receives data before the ownership handoff, so extensions must understand that temporarily present data is still being imported. Valkey 9 RC2, released on September 23, requires modules to declare that they support this behavior. Without the declaration, the server refuses the new migration operation when an incompatible module is loaded.
The change is more consequential than an extra capability bit. The module API documentation in the candidate says modules should set the option only if they understand that keys can load before slot ownership transfers. This identifies the assumption that an extension must revisit. Ordinary persistence support alone cannot establish that its behavior is correct during this interval.
I value Valkey's compatibility with established Redis operations, but extension compatibility needs a more specific contract here. A module can load successfully and still lack the logic required for a new cluster operation. Refusing that operation until the module declares support is a reasonable default.
A loaded module participates in the decision
The option is named VALKEYMODULE_OPTIONS_HANDLE_ATOMIC_SLOT_MIGRATION. The module sets it through its module options. At migration time the server iterates loaded modules and checks for the declaration, returning an error that names a module which lacks support. The test concerns the set of loaded extensions, so enabling the server feature alone does not establish availability.
This has a direct operational consequence. An installation can run the candidate and retain a module's ordinary commands while the new migration command remains unavailable. Diagnosing that result requires inspecting the module declaration, rather than assuming the server failed to recognize its own command. The returned error explains the missing capability.
The declaration is also a claim by the module, not an implementation of the required behavior. Adding the flag without examining how imported keys affect the module's state would merely suppress the server's protection. Correctness still depends on the extension handling the lifecycle it claims to support, including abandoned imports and completed ownership changes.
Migration events identify the relevant lifecycle
The implementation in pull request 2593 supplies server events alongside the opt-in requirement. Modules receive import and export lifecycle notifications, with completion and abort outcomes. Event information includes the slot ranges and source and target node identities, together with the migration job's name.
That information connects a callback to a specific operation. A module can distinguish which slots the event concerns without inferring them from unrelated key activity. Source and target identities also describe the transfer's direction. The event's job identity is useful when more than one migration has appeared in the server's recent history.
The patch defers an import-aborted notification until cleanup completes. That ordering matters because an aborted operation can leave temporary imported data to remove. A lifecycle event needs a defined relationship to that cleanup if a module uses it to update its own bookkeeping. Otherwise a module could interpret abort as evidence that all temporary state has already disappeared when it has not.
The public event header also versions event data. Its comments explain why older event identifiers and data versions must remain usable when new versions are added. A module compiled with a newer header should not accidentally require a newer event structure unless its author selected that structure. Compatibility here includes the shape of callback data as well as command names.
Functions do not belong to each migrated slot
Another RC2 correction removes function loading from atomic slot snapshots. Pull request 2547 explains that a destination which already has the function can reject FUNCTION LOAD. Propagating that duplicate load to the destination's replica can also cause a failure under the relevant propagation-error behavior.
The repair removes function rewriting from the slot snapshot. Its tests migrate data between nodes with functions already present, and also load functions while the incremental migration stream is active. The intended outcome separates slot data movement from distributing the server's function library. A resharding operation should not treat that library as if it were an ordinary member of every slot.
That distinction gives the module change useful context. Both corrections concern state outside the simple collection of keys being copied. Functions have a scope that differs from a slot's keys, while modules can maintain relationships which key loading alone does not fully describe. The migration implementation needs explicit rules for these different kinds of state.
Snapshotting has its own process identity
Pull request 2533 separates the slot-migration snapshot process from ordinary RDB snapshotting. It introduces a dedicated child-process type and separate copy-on-write accounting for migration. Completion and termination handling can then identify the work as a slot migration instead of sharing the ordinary snapshot's identity.
This is useful for both implementation and observation. A snapshot used to move slots has a different destination and lifecycle from a snapshot serving normal replication or persistence. Sharing machinery is possible, but the server still needs to route completion and failure to the right owner. The refactor makes that ownership more explicit.
RC2 also changes failover delays relative to node timeout. The patch scales delay components while preserving limits and ranking considerations. It addresses timing assumptions around cluster recovery, separately from the module declaration. These are incremental changes to the cluster behavior around the new migration procedure.
I regard this candidate's main contribution as a clearer account of which participants are ready for the operation. The core can transfer keys, but loaded extensions must understand imported data and its lifecycle. Function libraries remain outside slot transfer, and migration snapshots have dedicated process accounting. Those distinctions let an operator interpret a refused or completed migration with more precise information.