feat(nfm): enforce the NF heart-beat procedure - #95
Open
Niahh wants to merge 5 commits into
Open
Conversation
Niahh
force-pushed
the
feat/nf-heartbeat
branch
2 times, most recently
from
August 5, 2026 16:47
21b7465 to
2b4d860
Compare
Implement TS 29.510 clause 5.2.2.3: track the last heart-beat per profile, suspend instances silent past timer * suspendFactor and, when dropDelay is set, deregister them after that many more seconds in SUSPENDED. The sweeps claim instances atomically, so replicas sharing a database notify disjoint sets, and any heart-beat lifts a suspension. The NRF now owns the interval: advertised at registration, rejected on patch. Suspended instances leave discovery and validityPeriod tracks the suspension deadline instead of a hardcoded 100. Deregistration stays opt-in, waits out a startup grace and requires a stale heart-beat; an NF re-registers on a heart-beat 404, so an instance dropped while still alive returns on its next heart-beat. Remove the shutdown collection drop: profiles outlive the process, and a terminating replica must not deregister the network.
Niahh
force-pushed
the
feat/nf-heartbeat
branch
from
August 5, 2026 16:53
2b4d860 to
36e22ba
Compare
A whole-document op (path "") never matches the path guards in validateNfProfilePatch, so an NF could rename its own nfInstanceId or set its own heartBeatTimer. Check the applied result against the stored profile before persisting.
The interval is baked into the profile at registration while the sweeps use the current configuration: lowering the timer left registered NFs ticking at the old interval and flapping into SUSPENDED. Stamp the configured value on every heart-beat so the 200 response carries it.
Both sweeps claim documents by nfStatus plus timestamp on every tick; without an index each claim scans the collection.
A revived instance kept its old stamp; the drop sweep only tolerates that because it also requires a stale lastHeartBeat.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hello,
This PR is part of a series of PRs that will also modify the SBI NFs and the configuration file. The util PR adds the shared heart-beat runner those NFs use to answer the enforcement introduced here.
free5gc/util#48
free5gc/ausf#67
It addresses the following:
Presentation of the changes
NfProfile collection drop on shutdown
The NRF no longer touches the registry on shutdown: profiles outlive the process that accepted them, and with several replicas sharing one database, a single terminating pod must not deregister the whole network. Stale instances are handled by the heart-beat feature below instead. The registration counter that only served the shutdown wait (
NfRegistNum,AddNfRegister,DelNfRegister,waitNfDeregister) goes with it.Validity Period
Discovery responses now advertise a validityPeriod of timer * suspendFactor instead of the hardcoded 100s, so a consumer honouring it stops caching results longer than the NRF can vouch for the instances' liveness.
Heart-beat feature
The current behavior is to echo the heartBeatTimer back to the registering NF without enforcing it.
In a deployment scenario where an NF does not deregister properly and gets killed, we end up with stale profiles in the database. The 3GPP spec indicates that the NRF can set an NF's status to SUSPENDED when it has not been heard from within a configured period of time. Registration and every NFUpdate stamp a lastHeartBeat on the profile document. A sweeper ticks once per heart-beat interval and moves instances silent for timer * suspendFactor seconds to SUSPENDED, takes them out of discovery, and notifies their subscribers.
Each instance is claimed with an atomic findOneAndUpdate, so replicas sharing a database notify disjoint sets. The deadline uses the configured timer, never the stored profile's, which an NF could inflate.
Any heart-beat lifts a suspension, including a load-only NFUpdate that does not write nfStatus itself, or a suspended instance that kept heart-beating would stay SUSPENDED forever. The suspendedAt stamp is cleared with it, so the drop sweep never sees a stale stamp on a live instance.
Deregistration of suspended instances is opt-in, via dropDelay. When it is set and an NF stays SUSPENDED for more than dropDelay seconds, its profile is removed with the same effects as NFDeregister (notifications, urilist clean-up, OAuth cert removal). Since an NF started without a pinned nfInstanceId registers under a new one each boot, this is what keeps stale records from accumulating. When dropDelay is not set, the NRF suspends but never deletes.
Several guards keep the drop sweep from claiming a live instance: the delay counts from suspendedAt, an instance with a fresh lastHeartBeat is never claimed, findOneAndDelete claims atomically so subscribers hear DEREGISTERED once, and the sweep stays quiet for one suspension deadline plus one interval after startup, since while the NRF was down no instance could lift its suspension. Beyond that, an NF re-registers on a heart-beat 404, so an instance dropped while still alive is back in the registry on its next heart-beat.
Patch validation
validateNfProfilePatchguards paths, but a whole-document op (path"", RFC 6901) matches no path guard, so an NF could rename its own nfInstanceId or set its own heartBeatTimer through one. The applied result is now compared against the stored profile before it is persisted, and the update is rejected with a 400 when an NRF-owned field changed.UpdateNFInstanceProcedurealso answers 404 when the instance was deregistered between the patch write and the read-back, instead of failing on a nil document.New configuration IE:
The block itself can be omitted. timer and suspendFactor are optional and default to 10 and 2. dropDelay has no default: leaving it unset disables deregistration entirely. When set, config load rejects a value at or below timer * suspendFactor, since that would deregister instances the moment they are suspended.
Testing
This work is sponsored by Free Mobile!