I have recently been thinking a bit about how to do pilot testing of new functionality in production without having downtime. Fx. by marking users in a JWT token and then sending them to a pilot pool of servers based on that marking when the request hits the load balancer.

The test server and nginx configuration below does this by using the auth_request option to send the decision to an external server. Right now it just does round-robin, but the nodejs server could easily do the decision based on the content of a JWT token or looking up in an external database.

const http = require('http');

var count = 1;

const auth_server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('X-Pilot', (count++ % 2 > 0) ?  'A' : 'B'); // Do round-robin
  res.end();
});

auth_server.listen(3000, "localhost", () => {
  console.log("Server running at http://localhost:3000");
});

const server1 = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World 1\n');
});

server1.listen(3001, "localhost", () => {
  console.log("Server running at http://localhost:3001");
});

const server2 = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World 2\n');
});

server2.listen(3002, "localhost", () => {
  console.log("Server running at http://localhost:3002");
});
upstream auth_upstream {
  server 127.0.0.1:3000;
}

upstream app1_base_upstream {
  server 127.0.0.1:3001;
}

upstream app1_pilotA_upstream {
  server 127.0.0.1:3002;
}

map $xpilot $app1_pool {
  default "app1_base_upstream";
  A "app1_pilotA_upstream";
}

server {
  listen 80;
  server_name www.company.com;

  location / {
    auth_request /_auth;
    auth_request_set $xpilot $upstream_http_x_pilot;
    proxy_pass http://$app1_pool;
    add_header X-Pilot-Pool $app1_pool;
  }

  location /_auth {
    internal;

    proxy_pass_request_body off;
    proxy_pass_request_headers off;
    proxy_set_header Content-Length 0;

    proxy_pass http://$auth_upstream;
  }
}