graphile / crystal

🔮 Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!
https://graphile.org/
Other
12.63k stars 572 forks source link

Server-side events connection failing to keep-alive through Koa middleware #522

Closed zopf closed 6 years ago

zopf commented 7 years ago

When I run postgraphql as middleware in my Koa app, I frequently see a warning message like:

MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 schemas:changed listeners added. Use emitter.setMaxListeners() to increase limit

The warning usually appears after perhaps 5-30 seconds of node execution.

After digging in, I realized that it must be that many requests were being made to setupServerSentEvents without properly unsubscribing from the schemas:changed event type. (link)

Looking at the browser-server traffic, I'm seeing that when I open http://localhost:3000/graphiql in Chrome Version 59.0.3071.115 (Official Build) (64-bit), PostgraphiQL.js seems to be trying and failing to make a kept-alive event emitter connection to the server here, and then repeating this every couple seconds. Instead of maintaining a persistent event listener connection, it is opening and immediately erroring one, apparently, although when I look in the Network tab of the Chrome inspector, I see a 200 OK response to the request to http://localhost:3000/_postgraphql/stream. The connection stays open for only about 4ms.

Here's the request headers:

Request URL:http://localhost:3000/_postgraphql/stream
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:3000
Referrer Policy:no-referrer-when-downgrade

--- Response Headers
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
Date: Thu, 20 Jul 2017 17:30:04 GMT
Transfer-Encoding: chunked

--- Request Headers
GET /_postgraphql/stream HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: text/event-stream
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Referer: http://localhost:3000/graphiql
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: connect.sid=s%3AgwYPxer2G%2FMYhz6b1xqIzJs2.zIMxjJjNc0g0zl0ky5Zb0SljhBtohQlqm2qkibcKS18; _ga=GA1.1.329948811.1449158926

And here's the request response:

event: open

OK

For clarity, here is the code I'm using to set up postgraphql as middleware:

import * as Koa from 'koa';
import { postgraphql, PostGraphQLOptions } from 'postgraphql';

const app = new Koa();

// set up PostGraphQL
const postgresCnx: string = [...]
const schemaName: string = [...]
const options: PostGraphQLOptions = {
    "graphqlRoute": "/_graphql",
    "graphiqlRoute": "/graphiql",
    "graphiql": true,
    "jwtSecret": "my_secret",
    "pgDefaultRole": "my_anonymous",
    "jwtPgTypeIdentifier": "my.jwt_token",
    "watchPg": true,
    "bodySizeLimit": "1mb"
};
app.use(postgraphql(postgresCnx, schemaName, options));

const port = process.env.PORT || 3000;
app.listen(port);

Is there anything special that I need to do to get the server-side events listener to work with Koa when using postgraphql as middleware?

benjie commented 7 years ago

I've never used server sent events on Koa; perhaps you can use your knowledge of Koa to help us figure out the issue?

Here's where requestHandler triggers the server sent events:

https://github.com/postgraphql/postgraphql/blob/7272d611242c54d88a5932e7c66733d9f4020e04/src/postgraphql/http/createPostGraphQLHttpRequestHandler.js#L207-L215

And here's the server sent events file:

https://github.com/postgraphql/postgraphql/blob/master/src/postgraphql/http/setupServerSentEvents.js

And here's where we sort of hack Koa support:

https://github.com/postgraphql/postgraphql/blob/7272d611242c54d88a5932e7c66733d9f4020e04/src/postgraphql/http/createPostGraphQLHttpRequestHandler.js#L463-L472

It sounds like, unsurprisingly, Koa doesn't trigger the close event: https://github.com/postgraphql/postgraphql/blob/master/src/postgraphql/http/setupServerSentEvents.js#L34-L37

benjie commented 6 years ago

Does koa-connect solve this issue?

I think what's needed is a separate middleware for koa, the compatibility isn't working 100%.

benjie commented 6 years ago

Fixed in https://github.com/graphile/postgraphile/pull/782 🎉