some Honeycomb fixes

We got bit by the "can't run anything after the response finishes" thing

so I'm just forcing the response to wait for Honeycomb submit to finish

I hope this isn't like, just awful for perf lol. but puts to honeycomb seem fast?
This commit is contained in:
Emi Matchu 2020-08-17 01:16:35 -07:00
parent ce028e4956
commit f7997b4dc9
4 changed files with 59 additions and 44 deletions

View file

@ -1,5 +1,25 @@
const beeline = require("honeycomb-beeline")({
writeKey: process.env["HONEYCOMB_WRITE_KEY"],
dataset:
process.env["NODE_ENV"] === "production"
? "Dress to Impress (2020)"
: "Dress to Impress (2020, dev)",
serviceName: "impress-2020-gql-server",
});
const { ApolloServer } = require("../src/server/lib/apollo-server-vercel"); const { ApolloServer } = require("../src/server/lib/apollo-server-vercel");
const { config } = require("../src/server"); const { config } = require("../src/server");
const server = new ApolloServer(config); const server = new ApolloServer(config);
module.exports = server.createHandler(); const serverHandler = server.createHandler();
export default async (req, res) => {
await serverHandler(req, res);
// As a sneaky trick, we require the Honeycomb trace to finish before the
// request formally finishes. This... is technically a slowdown, I'm not sure
// how much of one. Hopefully not too much?
// https://vercel.com/docs/platform/limits#streaming-responses
await beeline.flush();
res.end();
};

View file

@ -1,12 +1,3 @@
require("honeycomb-beeline")({
writeKey: process.env["HONEYCOMB_WRITE_KEY"],
dataset:
process.env["NODE_ENV"] === "production"
? "Dress to Impress (2020)"
: "Dress to Impress (2020, dev)",
serviceName: "impress-2020-gql-server",
});
const { gql, makeExecutableSchema } = require("apollo-server"); const { gql, makeExecutableSchema } = require("apollo-server");
import { addBeelineToSchema, beelinePlugin } from "./lib/beeline-graphql"; import { addBeelineToSchema, beelinePlugin } from "./lib/beeline-graphql";

View file

@ -17,35 +17,37 @@ function graphqlVercel(options) {
); );
} }
const graphqlHandler = (req, res) => { const graphqlHandler = async (req, res) => {
if (req.httpMethod === "POST" && !req.body) { if (req.httpMethod === "POST" && !req.body) {
return res.status(500).send("POST body missing."); res.status(500).write("POST body missing.");
return;
} }
runHttpQuery([req, res], { let result;
method: req.method, try {
options: options, result = await runHttpQuery([req, res], {
query: req.method === "POST" && req.body ? req.body : req.query,
request: {
url: req.path,
method: req.method, method: req.method,
headers: new Headers(req.headers), options: options,
}, query: req.method === "POST" && req.body ? req.body : req.query,
}).then( request: {
({ graphqlResponse, responseInit }) => { url: req.path,
setHeaders(res, new Headers(responseInit.headers)).send( method: req.method,
graphqlResponse headers: new Headers(req.headers),
); },
}, });
(error) => { } catch (error) {
if ("HttpQueryError" !== error.name) { if ("HttpQueryError" !== error.name) {
console.error(error); console.error(error);
return; return;
}
setHeaders(res, new Headers(error.headers))
.status(error.statusCode)
.send(error.message);
} }
); setHeaders(res, new Headers(error.headers))
.status(error.statusCode)
.write(error.message);
return;
}
const { graphqlResponse, responseInit } = result;
setHeaders(res, new Headers(responseInit.headers));
res.write(graphqlResponse);
}; };
return graphqlHandler; return graphqlHandler;
@ -122,7 +124,7 @@ class ApolloServer extends ApolloServerBase {
} }
} }
return (req, res) => { return async (req, res) => {
// Make a request-specific copy of the CORS headers, based on the server // Make a request-specific copy of the CORS headers, based on the server
// global CORS headers we've set above. // global CORS headers we've set above.
const requestCorsHeaders = new Headers(corsHeaders); const requestCorsHeaders = new Headers(corsHeaders);
@ -164,7 +166,8 @@ class ApolloServer extends ApolloServerBase {
); );
if (res.method === "OPTIONS") { if (res.method === "OPTIONS") {
setHeaders(res, requestCorsHeadersObject).status(204).send(""); setHeaders(res, requestCorsHeadersObject).status(204);
return;
} }
if (this.playgroundOptions && req.method === "GET") { if (this.playgroundOptions && req.method === "GET") {
@ -177,7 +180,7 @@ class ApolloServer extends ApolloServerBase {
...this.playgroundOptions, ...this.playgroundOptions,
}; };
return setHeaders( setHeaders(
res, res,
new Headers({ new Headers({
"Content-Type": "text/html", "Content-Type": "text/html",
@ -185,11 +188,12 @@ class ApolloServer extends ApolloServerBase {
}) })
) )
.status(200) .status(200)
.send(renderPlaygroundPage(playgroundRenderPageOptions)); .write(renderPlaygroundPage(playgroundRenderPageOptions));
return;
} }
} }
graphqlVercel(async () => { await graphqlVercel(async () => {
// In a world where this `createHandler` was async, we might avoid this // In a world where this `createHandler` was async, we might avoid this
// but since we don't want to introduce a breaking change to this API // but since we don't want to introduce a breaking change to this API
// (by switching it to `async`), we'll leverage the // (by switching it to `async`), we'll leverage the

View file

@ -18,8 +18,6 @@ export function addBeelineToSchema(schema) {
result = oldResolve(source, args, { ...context, span }, info); result = oldResolve(source, args, { ...context, span }, info);
if (result.then) await result; if (result.then) await result;
} catch (error) { } catch (error) {
// TODO(matchu): Not sure why this is here, it seems like we should
// re-throw the error, and even then this seems to not be happening?
span.addContext({ "error.message": error.message }); span.addContext({ "error.message": error.message });
span.addContext({ "error.stacktrace": error.stack }); span.addContext({ "error.stacktrace": error.stack });
} }
@ -75,8 +73,10 @@ export const beelinePlugin = {
const trace = beeline.startTrace(); const trace = beeline.startTrace();
return { return {
didResolveOperation({ operationName }) { didResolveOperation({ operationName }) {
trace.payload["name"] = operationName; beeline.addContext({
trace.payload["operation_name"] = operationName; name: operationName,
operation_name: operationName,
});
}, },
willSendResponse() { willSendResponse() {
beeline.finishTrace(trace); beeline.finishTrace(trace);