ftx-api
ftx-api copied to clipboard
How to handle "ping / pong" things?
After 1 hour of working, websocket connection crashes.
Do I need to response on this: [ 'Websocket event: ', '{"type":"pong"}' ]
?
Is there any method like this or something?
client.on('ping', () => { client.pong(); });
This library already has ping/pong heartbeats in the websocket client. You can monitor them by enabling the "silly" logs: https://github.com/tiagosiebler/ftx-api/blob/master/src/websocket-client.ts#L343-L346
At regular intervals (pingInterval) the library sends upstream pings. The ws client expects to receive a pong frame OR any message on that connection (onWsMessage) before a timer expires (pongTimeout). If neither of those happen in time, the connection is assumed dead and it's respawned automatically after a tear down.
If that happens, you'll see a info log message like this: 'Pong timeout - clearing timers & closing socket to reconnect'
What happens when you say it crashes? Can you reproduce this with every topic or only specific ones?
Here is my error below. I don't know what is it. It happens after 1 hour of running.
node:internal/process/promises:265 triggerUncaughtException(err, true /* fromPromise */); ^ AxiosError: getaddrinfo ENOTFOUND ftx.com at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26) { hostname: 'ftx.com', syscall: 'getaddrinfo', code: 'ENOTFOUND', errno: -3008, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [Function: httpAdapter], transformRequest: [ [Function: transformRequest] ], transformResponse: [ [Function: transformResponse] ], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: [Function: FormData] { LINE_BREAK: '\r\n', DEFAULT_CONTENT_TYPE: 'application/octet-stream' } }, validateStatus: [Function: validateStatus], headers: { Accept: 'application/json, text/plain, */*', 'User-Agent': 'axios/0.27.2' }, url: 'https://ftx.com/api/futures', method: 'get', data: undefined }, request: <ref *3> Writable { _writableState: WritableState { objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: false, decodeStrings: true, defaultEncoding: 'utf8', length: 0, writing: false, corked: 0, sync: true, bufferProcessing: false, onwrite: [Function: bound onwrite], writecb: null, writelen: 0, afterWriteTickInfo: null, buffered: [], bufferedIndex: 0, allBuffers: true, allNoop: true, pendingcb: 0, constructed: true, prefinished: false, errorEmitted: false, emitClose: true, autoDestroy: true, errored: null, closed: false, closeEmitted: false, [Symbol(kOnFinished)]: [] }, _events: [Object: null prototype] { response: [Function: handleResponse], error: [Function: handleRequestError], socket: [Function: handleRequestSocket] }, _eventsCount: 3, _maxListeners: undefined, _options: { maxRedirects: 21, maxBodyLength: 10485760, protocol: 'https:', path: '/api/futures', method: 'GET', headers: { Accept: 'application/json, text/plain, */*', 'User-Agent': 'axios/0.27.2' }, agent: undefined, agents: { http: undefined, https: undefined }, auth: undefined, hostname: 'ftx.com', port: null, nativeProtocols: { 'http:': { _connectionListener: [Function: connectionListener], METHODS: [ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT', 'REBIND', 'REPORT', 'SEARCH', 'SOURCE', 'SUBSCRIBE', 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE' ], STATUS_CODES: { '100': 'Continue', '101': 'Switching Protocols', '102': 'Processing', '103': 'Early Hints', '200': 'OK', '201': 'Created', '202': 'Accepted', '203': 'Non-Authoritative Information', '204': 'No Content', '205': 'Reset Content', '206': 'Partial Content', '207': 'Multi-Status', '208': 'Already Reported', '226': 'IM Used', '300': 'Multiple Choices', '301': 'Moved Permanently', '302': 'Found', '303': 'See Other', '304': 'Not Modified', '305': 'Use Proxy', '307': 'Temporary Redirect', '308': 'Permanent Redirect', '400': 'Bad Request', '401': 'Unauthorized', '402': 'Payment Required', '403': 'Forbidden', '404': 'Not Found', '405': 'Method Not Allowed', '406': 'Not Acceptable', '407': 'Proxy Authentication Required', '408': 'Request Timeout', '409': 'Conflict', '410': 'Gone', '411': 'Length Required', '412': 'Precondition Failed', '413': 'Payload Too Large', '414': 'URI Too Long', '415': 'Unsupported Media Type', '416': 'Range Not Satisfiable', '417': 'Expectation Failed', '418': "I'm a Teapot", '421': 'Misdirected Request', '422': 'Unprocessable Entity', '423': 'Locked', '424': 'Failed Dependency', '425': 'Too Early', '426': 'Upgrade Required', '428': 'Precondition Required', '429': 'Too Many Requests', '431': 'Request Header Fields Too Large', '451': 'Unavailable For Legal Reasons', '500': 'Internal Server Error', '501': 'Not Implemented', '502': 'Bad Gateway', '503': 'Service Unavailable', '504': 'Gateway Timeout', '505': 'HTTP Version Not Supported', '506': 'Variant Also Negotiates', '507': 'Insufficient Storage', '508': 'Loop Detected', '509': 'Bandwidth Limit Exceeded', '510': 'Not Extended', '511': 'Network Authentication Required' }, Agent: [Function: Agent] { defaultMaxSockets: Infinity }, ClientRequest: [Function: ClientRequest], IncomingMessage: [Function: IncomingMessage], OutgoingMessage: [Function: OutgoingMessage], Server: [Function: Server], ServerResponse: [Function: ServerResponse], createServer: [Function: createServer], validateHeaderName: [Function: __node_internal_], validateHeaderValue: [Function: __node_internal_], get: [Function: get], request: [Function: request], maxHeaderSize: [Getter], globalAgent: [Getter/Setter] }, 'https:': { Agent: [Function: Agent], globalAgent: Agent { _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object: null prototype], requests: [Object: null prototype] {}, sockets: [Object: null prototype], freeSockets: [Object: null prototype] {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: Infinity, maxFreeSockets: 256, scheduling: 'lifo', maxTotalSockets: Infinity, totalSocketCount: 1, maxCachedSessions: 100, _sessionCache: [Object], [Symbol(kCapture)]: false }, Server: [Function: Server], createServer: [Function: createServer], get: [Function: get], request: [Function: request] } }, pathname: '/api/futures' }, _ended: true, _ending: true, _redirectCount: 0, _redirects: [], _requestBodyLength: 0, _requestBodyBuffers: [], _onNativeResponse: [Function (anonymous)], _currentRequest: <ref *1> ClientRequest { _events: [Object: null prototype] { response: [Function: bound onceWrapper] { listener: [Function (anonymous)] }, abort: [Function (anonymous)], aborted: [Function (anonymous)], connect: [Function (anonymous)], error: [Function (anonymous)], socket: [Function (anonymous)], timeout: [Function (anonymous)] }, _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: true, chunkedEncoding: false, shouldKeepAlive: false, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: false, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: false, socket: <ref *2> TLSSocket { _tlsOptions: { allowHalfOpen: undefined, pipe: false, secureContext: SecureContext { context: SecureContext {} }, isServer: false, requestCert: true, rejectUnauthorized: true, session: Buffer(1674) [Uint8Array] [ 48, 130, 6, 134, 2, 1, 1, 2, 2, 3, 4, 4, 2, 19, 2, 4, 32, 125, 161, 63, 174, 86, 115, 34, 207, 73, 71, 212, 236, 196, 60, 230, 85, 253, 31, 6, 34, 137, 177, 90, 103, 240, 189, 183, 31, 40, 19, 190, 177, 4, 48, 241, 165, 217, 10, 1, 58, 144, 132, 167, 202, 165, 92, 36, 223, 231, 48, 208, 236, 0, 138, 116, 85, 133, 42, 144, 158, 211, 4, 87, 70, 249, 145, 120, 98, 212, 243, 136, 206, 247, 34, 144, 172, 102, 40, 101, 24, 145, 238, 161, ... 1574 more items ], ALPNProtocols: undefined, requestOCSP: undefined, enableTrace: undefined, pskCallback: undefined, highWaterMark: undefined, onread: undefined, signal: undefined }, _secureEstablished: false, _securePending: false, _newSessionPending: false, _controlReleased: true, secureConnecting: true, _SNICallback: null, servername: null, alpnProtocol: null, authorized: false, authorizationError: null, encrypted: true, _events: [Object: null prototype] { close: [ [Function: onSocketCloseDestroySSL], [Function], [Function: onClose], [Function: socketCloseListener] ], end: [ [Function: onConnectEnd], [Function: onReadableStreamEnd] ], newListener: [Function: keylogNewListener], connect: [ [Function], [Function], [Function] ], secure: [Function: onConnectSecure], session: [Function (anonymous)], free: [Function: onFree], timeout: [Function: onTimeout], agentRemove: [Function: onRemove], error: [Function: socketErrorListener], drain: [Function: ondrain] }, _eventsCount: 11, connecting: false, _hadError: true, _parent: null, _host: 'ftx.com', _readableState: ReadableState { objectMode: false, highWaterMark: 16384, buffer: BufferList { head: null, tail: null, length: 0 }, length: 0, pipes: [], flowing: true, ended: false, endEmitted: false, reading: true, constructed: true, sync: false, needReadable: true, emittedReadable: false, readableListening: false, resumeScheduled: false, errorEmitted: true, emitClose: false, autoDestroy: true, destroyed: true, errored: Error: getaddrinfo ENOTFOUND ftx.com at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26) { errno: -3008, code: 'ENOTFOUND', syscall: 'getaddrinfo', hostname: 'ftx.com' }, closed: true, closeEmitted: true, defaultEncoding: 'utf8', awaitDrainWriters: null, multiAwaitDrain: false, readingMore: false, dataEmitted: false, decoder: null, encoding: null, [Symbol(kPaused)]: false }, _maxListeners: undefined, _writableState: WritableState { objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: true, decodeStrings: false, defaultEncoding: 'utf8', length: 132, writing: true, corked: 0, sync: false, bufferProcessing: false, onwrite: [Function: bound onwrite], writecb: [Function: bound onFinish], writelen: 132, afterWriteTickInfo: null, buffered: [], bufferedIndex: 0, allBuffers: true, allNoop: true, pendingcb: 1, constructed: true, prefinished: false, errorEmitted: true, emitClose: false, autoDestroy: true, errored: Error: getaddrinfo ENOTFOUND ftx.com at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26) { errno: -3008, code: 'ENOTFOUND', syscall: 'getaddrinfo', hostname: 'ftx.com' }, closed: true, closeEmitted: true, [Symbol(kOnFinished)]: [] }, allowHalfOpen: false, _sockname: null, _pendingData: 'GET /api/futures HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Host: ftx.com\r\n' + 'Connection: close\r\n' + '\r\n', _pendingEncoding: 'latin1', server: undefined, _server: null, ssl: null, _requestCert: true, _rejectUnauthorized: true, parser: null, _httpMessage: [Circular *1], [Symbol(res)]: TLSWrap { _parent: TCP { reading: [Getter/Setter], onconnection: null, [Symbol(owner_symbol)]: [Circular *2], [Symbol(handle_onclose)]: [Function: done] }, _parentWrap: undefined, _secureContext: SecureContext { context: SecureContext {} }, reading: false, onkeylog: [Function: onkeylog], onhandshakestart: {}, onhandshakedone: [Function (anonymous)], onocspresponse: [Function: onocspresponse], onnewsession: [Function: onnewsessionclient], onerror: [Function: onerror], [Symbol(owner_symbol)]: [Circular *2] }, [Symbol(verified)]: false, [Symbol(pendingSession)]: null, [Symbol(async_id_symbol)]: 336098, [Symbol(kHandle)]: null, [Symbol(kSetNoDelay)]: false, [Symbol(lastWriteQueueSize)]: 0, [Symbol(timeout)]: null, [Symbol(kBuffer)]: null, [Symbol(kBufferCb)]: null, [Symbol(kBufferGen)]: null, [Symbol(kCapture)]: false, [Symbol(kBytesRead)]: 0, [Symbol(kBytesWritten)]: 0, [Symbol(connect-options)]: { rejectUnauthorized: true, ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA', checkServerIdentity: [Function: checkServerIdentity], minDHSize: 1024, session: Buffer(1674) [Uint8Array] [ 48, 130, 6, 134, 2, 1, 1, 2, 2, 3, 4, 4, 2, 19, 2, 4, 32, 125, 161, 63, 174, 86, 115, 34, 207, 73, 71, 212, 236, 196, 60, 230, 85, 253, 31, 6, 34, 137, 177, 90, 103, 240, 189, 183, 31, 40, 19, 190, 177, 4, 48, 241, 165, 217, 10, 1, 58, 144, 132, 167, 202, 165, 92, 36, 223, 231, 48, 208, 236, 0, 138, 116, 85, 133, 42, 144, 158, 211, 4, 87, 70, 249, 145, 120, 98, 212, 243, 136, 206, 247, 34, 144, 172, 102, 40, 101, 24, 145, 238, 161, ... 1574 more items ], maxRedirects: 21, maxBodyLength: 10485760, protocol: 'https:', path: null, method: 'GET', headers: { Accept: 'application/json, text/plain, */*', 'User-Agent': 'axios/0.27.2' }, agent: undefined, agents: { http: undefined, https: undefined }, auth: undefined, hostname: 'ftx.com', port: 443, nativeProtocols: { 'http:': [Object], 'https:': [Object] }, pathname: '/api/futures', _defaultAgent: Agent { _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object: null prototype], requests: [Object: null prototype] {}, sockets: [Object: null prototype], freeSockets: [Object: null prototype] {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: Infinity, maxFreeSockets: 256, scheduling: 'lifo', maxTotalSockets: Infinity, totalSocketCount: 1, maxCachedSessions: 100, _sessionCache: [Object], [Symbol(kCapture)]: false }, host: 'ftx.com', servername: 'ftx.com', _agentKey: 'ftx.com:443:::::::::::::::::::::', encoding: null, singleUse: true } }, _header: 'GET /api/futures HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Host: ftx.com\r\n' + 'Connection: close\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: Agent { _events: [Object: null prototype] { free: [Function (anonymous)], newListener: [Function: maybeEnableKeylog] }, _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object: null prototype] { path: null }, requests: [Object: null prototype] {}, sockets: [Object: null prototype] { 'ftx.com:443:::::::::::::::::::::': [ [TLSSocket] ] }, freeSockets: [Object: null prototype] {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: Infinity, maxFreeSockets: 256, scheduling: 'lifo', maxTotalSockets: Infinity, totalSocketCount: 1, maxCachedSessions: 100, _sessionCache: { map: { 'ftx.com:443:::::::::::::::::::::': [Buffer [Uint8Array]], 'otc.ftx.com:443:::::::::::::::::::::': [Buffer [Uint8Array]] }, list: [ 'ftx.com:443:::::::::::::::::::::', 'otc.ftx.com:443:::::::::::::::::::::' ] }, [Symbol(kCapture)]: false }, socketPath: undefined, method: 'GET', maxHeaderSize: undefined, insecureHTTPParser: undefined, path: '/api/futures', _ended: false, res: null, aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'ftx.com', protocol: 'https:', _redirectable: [Circular *3], [Symbol(kCapture)]: false, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype] { accept: [ 'Accept', 'application/json, text/plain, */*' ], 'user-agent': [ 'User-Agent', 'axios/0.27.2' ], host: [ 'Host', 'ftx.com' ] } }, _currentUrl: 'https://ftx.com/api/futures', [Symbol(kCapture)]: false } } [nodemon] app crashed - waiting for file changes before starting...
AxiosError: getaddrinfo ENOTFOUND ftx.com
Looks like your network connection dropped, so it couldn't reach FTX servers.
url: 'https://ftx.com/api/futures', method: 'get'
Is your code executing listAllFutures()? https://github.com/tiagosiebler/ftx-api/blob/master/src/rest-client.ts#L186-L188
There's many errors talking about that GET endpoint from the REST API.
is it possible to receive pong events and also disable pong logging (looks to be on by default)?
You can disable the whole logging level (or customise it with your own logic) by injecting a custom logger into the websocket client:
const { WebsocketClient, DefaultLogger } = require('ftx-api');
// Disable all logging on the silly level
const customLogger = {
...DefaultLogger,
silly: () => {},
};
const ws = new WebsocketClient(
wsOptions,
customLogger
);
Regarding receiving pong events, the connector already handles pings and pong receipts for you, as well as reconnects if a pong doesn't arrive on time.
What's the use case for wanting to receive them too?
just keeping track of the last websocket event received. it's not a must have for the pong events but was just curious. appreciate the response.
just keeping track of the last websocket event received. it's not a must have for the pong events but was just curious. appreciate the response.
I see, I'm open to exposing something if you want a more granular view. Could be a lastEventAt timestamp, for example, if that's useful?
In the meantime you could also use the injected logger to also use log events as a sign a ws event came through. If you take a look at the ws client (specifically onWsMessage), you can see the different things you can expect.