Skip to content

Conversation

@bzp2010
Copy link
Collaborator

@bzp2010 bzp2010 commented Nov 28, 2025

Description

Note

This is a speculative fix. We cannot truly verify that the issue exists, but it is theoretically possible.

The APISIX Standalone backend uses a timestamp as conf_version and modified index. As required by the APISIX Admin API (for standalone), this value must be numeric and incrementally increasing.

Previously, we used Date.now() to get the latest millisecond timestamp from Node.js, which is obtained by libuv at a lower level via a system call. If the host's clock jumps forward due to regular time synchronisation from NTP or similar components, Date.now() might return a smaller, previous value. In short, this violates the rule that the configuration version must be monotonically increasing.

This problem is actually quite tricky, because it is difficult to establish a reliable timestamp that is monotonically increasing and also remains valid on a restart. Fortunately, this is not impossible; we combine two mechanisms to implement a timestamp mechanism that appears to be more reliable.

For a single ADC server process, when it starts up, we can get a start timestamp, which is stored as a static value in memory and remains fixed. We then use the Web Performance API (performance.now()) to get the seconds from the Node.js was started. After that, simply adding them together is enough to get an incremented timestamp.

Next, we must consider what happens if a time rollback occurs while the ADC is restarting.
When we perform the first sync after the ADC starts to build the cache, we extract the maximum configuration version number from the configuration pulled from APISIX and cache it. This way, if a new timestamp that the ADC wants to use is smaller than the one already applied in APISIX, we use the larger of the two to overwrite it, and then increment it there. This ensures that the Admin API can accept configuration change requests. Afterwards, when the time advance exceeds the old version number's timestamp, the sync continues with the standard process.

Strictly, APISIX does not enforce an "incrementing" constraint on the value of conf_version. It merely checks whether the new value matches the old one to execute actions such as rebuilding the routing tree or invalidating caches. Perhaps in future we may remove this incrementality constraint from the Admin API. As one of the first APISIX releases supporting this pattern, imposing stricter limitations helps us understand the boundaries and uncover potential issues. Should we deem it no longer essential in the future, we may remove it.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible

@bzp2010 bzp2010 added the test/apisix-standalone Trigger the APISIX standalone test on the PR label Nov 28, 2025
@bzp2010 bzp2010 merged commit 2e14e5a into main Nov 29, 2025
26 checks passed
@bzp2010 bzp2010 deleted the bzp/fix-bas-conf-version-rollback branch November 29, 2025 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test/apisix-standalone Trigger the APISIX standalone test on the PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants