Skip to content

Instantly share code, notes, and snippets.

@nginx-gists
Last active November 10, 2022 23:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nginx-gists/e99a65739b81a86dfd6b1823938c71db to your computer and use it in GitHub Desktop.
Save nginx-gists/e99a65739b81a86dfd6b1823938c71db to your computer and use it in GitHub Desktop.
Using the NGINX JavaScript Module to Progressively Transition Clients to a New Server
upstream old {
server 10.0.0.1;
server 10.0.0.2;
}
upstream new {
server 10.0.0.9;
server 10.0.0.10;
}
js_import /etc/nginx/progressive_transition.js;
js_set $upstream progressive_transition.transitionStatus; # Returns "old|new" based on window pos
server {
listen 80;
location / {
set $transition_window_start "Wed, 31 Aug 2016 17:00:00 +0100";
set $transition_window_end "Wed, 31 Aug 2016 19:00:00 +0100";
proxy_pass http://$upstream;
error_log /var/log/nginx/transition.log info; # Enable NJS logging
}
}
# vim: syntax=nginx
function fnv32a(str) {
var hval = 2166136261;
for (var i = 0; i < str.length; ++i ) {
hval ^= str.charCodeAt(i);
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
return hval >>> 0;
}
function transitionStatus(req) {
var vars, window_start, window_end, time_now, timepos, numhash, hashpos;
// Get the transition window from NGINX configuration
vars = req.variables;
window_start = new Date(vars.transition_window_start);
window_end = new Date(vars.transition_window_end);
// Are we in the transition time window?
time_now = Date.now();
if ( time_now < window_start ) {
return "old";
} else if ( time_now > window_end ) {
return "new";
} else { // We are in the transition window
// Calculate our position in the window (0-1)
timepos = (time_now - window_start) / (window_end - window_start);
// Get numeric hash for this client's IP address
numhash = fnv32a(req.remoteAddress);
// Calculate the hash's position in the output range (0-1)
hashpos = numhash / 4294967295; // Upper bound is 32 bits
req.log("timepos = " + timepos + ", hashpos = " + hashpos); //error_log [info]
// Should we transition this client?
if ( timepos > hashpos ) {
return "new";
} else {
return "old";
}
}
}
export default { transitionStatus }
@nginx-gists
Copy link
Author

nginx-gists commented Feb 8, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment