nodejs-etcd
nodejs-etcd copied to clipboard
Redirects break write
Occasionally etcd will spit back a redirect (in fact, almost always when http://localhost:4001 is used in our cluster) when a key is being written.
Should follow redirects.
An example request that breaks:
Write:
{ key: 'application/config/desktop_loggedin_refresh_interval',
value: '5' }
response:
{ _readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: true,
endEmitted: true,
reading: false,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: false,
domain: null,
_events:
{ end: [ [Function: responseOnEnd], [Function], [Function] ],
readable: [Function],
close: [ [Function], [Function] ],
data: [Function] },
_maxListeners: 10,
socket:
{ _connecting: false,
_handle:
{ fd: 16,
writeQueueSize: 0,
owner: [Circular],
onread: [Function: onread],
reading: true },
_readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: false,
endEmitted: false,
reading: true,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
free: [Function],
close: [Object],
agentRemove: [Function],
drain: [Function: ondrain] },
_maxListeners: 10,
_writableState:
{ highWaterMark: 16384,
objectMode: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
sync: false,
bufferProcessing: false,
onwrite: [Function],
writecb: null,
writelen: 0,
buffer: [],
errorEmitted: false },
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 240,
_bytesDispatched: 212,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_headerSent: true,
_header: 'PUT /v2/keys/application/config/desktop_loggedin_refresh_interval HTTP/1.1\r\nhost: localhost:4001\r\ncontent-type: application/x-www-form-urlencoded; charset=utf-8\r\ncontent-length: 7\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Circular],
connection: [Circular],
agent: [Object],
socketPath: undefined,
method: 'PUT',
path: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ondata: null },
connection:
{ _connecting: false,
_handle:
{ fd: 16,
writeQueueSize: 0,
owner: [Circular],
onread: [Function: onread],
reading: true },
_readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: false,
endEmitted: false,
reading: true,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
free: [Function],
close: [Object],
agentRemove: [Function],
drain: [Function: ondrain] },
_maxListeners: 10,
_writableState:
{ highWaterMark: 16384,
objectMode: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
sync: false,
bufferProcessing: false,
onwrite: [Function],
writecb: null,
writelen: 0,
buffer: [],
errorEmitted: false },
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 240,
_bytesDispatched: 212,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_headerSent: true,
_header: 'PUT /v2/keys/application/config/desktop_loggedin_refresh_interval HTTP/1.1\r\nhost: localhost:4001\r\ncontent-type: application/x-www-form-urlencoded; charset=utf-8\r\ncontent-length: 7\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Circular],
connection: [Circular],
agent: [Object],
socketPath: undefined,
method: 'PUT',
path: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ondata: null },
httpVersion: '1.1',
complete: true,
headers:
{ location: 'http://10.36.5.112:4001/v2/keys/application/config/desktop_loggedin_refresh_interval',
date: 'Mon, 17 Nov 2014 01:20:43 GMT',
'content-type': 'text/plain; charset=utf-8',
'transfer-encoding': 'chunked' },
trailers: {},
_pendings: [],
_pendingIndex: 0,
url: '',
method: null,
statusCode: 307,
client:
{ _connecting: false,
_handle:
{ fd: 16,
writeQueueSize: 0,
owner: [Circular],
onread: [Function: onread],
reading: true },
_readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: false,
endEmitted: false,
reading: true,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
free: [Function],
close: [Object],
agentRemove: [Function],
drain: [Function: ondrain] },
_maxListeners: 10,
_writableState:
{ highWaterMark: 16384,
objectMode: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
sync: false,
bufferProcessing: false,
onwrite: [Function],
writecb: null,
writelen: 0,
buffer: [],
errorEmitted: false },
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 240,
_bytesDispatched: 212,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_headerSent: true,
_header: 'PUT /v2/keys/application/config/desktop_loggedin_refresh_interval HTTP/1.1\r\nhost: localhost:4001\r\ncontent-type: application/x-www-form-urlencoded; charset=utf-8\r\ncontent-length: 7\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Circular],
connection: [Circular],
agent: [Object],
socketPath: undefined,
method: 'PUT',
path: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ondata: null },
_consuming: true,
_dumped: false,
httpVersionMajor: 1,
httpVersionMinor: 1,
upgrade: false,
req:
{ domain: null,
_events: { error: [Function], drain: [Function] },
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_headerSent: true,
_header: 'PUT /v2/keys/application/config/desktop_loggedin_refresh_interval HTTP/1.1\r\nhost: localhost:4001\r\ncontent-type: application/x-www-form-urlencoded; charset=utf-8\r\ncontent-length: 7\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket:
{ _connecting: false,
_handle: [Object],
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_maxListeners: 10,
_writableState: [Object],
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 240,
_bytesDispatched: 212,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage: [Circular],
ondata: null },
connection:
{ _connecting: false,
_handle: [Object],
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_maxListeners: 10,
_writableState: [Object],
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 240,
_bytesDispatched: 212,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage: [Circular],
ondata: null },
agent:
{ domain: null,
_events: [Object],
_maxListeners: 10,
options: {},
requests: {},
sockets: [Object],
maxSockets: 5,
createConnection: [Function] },
socketPath: undefined,
method: 'PUT',
path: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
_headers:
{ host: 'localhost:4001',
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
'content-length': 7 },
_headerNames:
{ host: 'host',
'content-type': 'content-type',
'content-length': 'content-length' },
parser: null,
res: [Circular] },
pipe: [Function],
addListener: [Function: addListener],
on: [Function: addListener],
pause: [Function],
resume: [Function],
read: [Function],
request:
{ domain: null,
_events:
{ error: [Function],
complete: [Function],
pipe: [Function],
end: [Object],
data: [Function] },
_maxListeners: 10,
readable: true,
writable: true,
method: 'PUT',
uri:
{ protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:4001',
port: '4001',
hostname: 'localhost',
hash: null,
search: null,
query: null,
pathname: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
path: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
href: 'http://localhost:4001/v2/keys/application/config/desktop_loggedin_refresh_interval' },
callback: [Function],
explicitMethod: true,
canTunnel:
{ httpOverHttp: [Function: httpOverHttp],
httpsOverHttp: [Function: httpsOverHttp],
httpOverHttps: [Function: httpOverHttps],
httpsOverHttps: [Function: httpsOverHttps],
debug: [Function] },
localAddress: undefined,
pool: {},
dests: [],
__isRequestRequest: true,
_callback: [Function],
_redirectsFollowed: 0,
maxRedirects: 10,
followRedirect: true,
followAllRedirects: false,
redirects: [],
headers:
{ 'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
'content-length': 7 },
setHost: true,
originalCookieHeader: undefined,
_disableCookies: true,
_jar: undefined,
port: '4001',
host: 'localhost',
clientErrorHandler: [Function],
_parserErrorHandler: [Function],
body: <Buffer 76 61 6c 75 65 3d 35>,
path: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
httpModule:
{ parsers: [Object],
STATUS_CODES: [Object],
IncomingMessage: [Object],
OutgoingMessage: [Object],
ServerResponse: [Object],
Agent: [Object],
globalAgent: [Object],
ClientRequest: [Object],
request: [Function],
get: [Function],
Server: [Object],
createServer: [Function],
_connectionListener: [Function: connectionListener],
Client: [Function: deprecated],
createClient: [Function: deprecated] },
agentClass: { [Function: Agent] super_: [Object], defaultMaxSockets: 5 },
agent:
{ domain: null,
_events: [Object],
_maxListeners: 10,
options: {},
requests: {},
sockets: [Object],
maxSockets: 5,
createConnection: [Function] },
_started: true,
href: 'http://localhost:4001/v2/keys/application/config/desktop_loggedin_refresh_interval',
req:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_headerSent: true,
_header: 'PUT /v2/keys/application/config/desktop_loggedin_refresh_interval HTTP/1.1\r\nhost: localhost:4001\r\ncontent-type: application/x-www-form-urlencoded; charset=utf-8\r\ncontent-length: 7\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Object],
connection: [Object],
agent: [Object],
socketPath: undefined,
method: 'PUT',
path: '/v2/keys/application/config/desktop_loggedin_refresh_interval',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ntick: true,
response: [Circular],
_ended: true,
_callbackCalled: true },
toJSON: [Function: toJSON],
body: '' } ''
I have a work around for the moment, it's a real hack job.
function rejigEtcd(resp) {
if (resp.headers.location) {
console.log('re-routing etcd requests to new server')
var uri = url.parse(resp.headers.location);
etcd.configure({url: uri.protocol + '//' + uri.host});
return true;
}
}
function Save(name, value) {
console.log('Saving: ', name, value);
etcd.write({key: name, value: value}, function(err, resp, body) {
if (err) {
console.log(err);
}
if (!body) {
if (rejigEtcd(resp)) {
Save(name, value);
} else {
console.log(resp);
}
}
});
}