I have this strange issue that keeps occurring with my google pub sub service. When I start my server, the google pub sub service works and there doesn't seem to be an issue. When I leave my server running for prolonged periods of time (a day or more), once in a while, I get the following error out of nowhere.
Error: 16 UNAUTHENTICATED: Failed to retrieve auth metadata with error: request to https://www.googleapis.com/oauth2/v4/token failed, reason: getaddrinfo ENOTFOUND www.googleapis.com
at Object.callErrorFromStatus ~\<project_path>\node_modules\@grpc\grpc-js\src\call.ts:81:24)
at Object.onReceiveStatus (~\<project_path>\node_modules\@grpc\grpc-js\src\client.ts:338:36)
at Object.onReceiveStatus (~\<project_path>\node_modules\@grpc\grpc-js\src\client-interceptors.ts:426:34)
at Object.onReceiveStatus (~\<project_path>\node_modules\@grpc\grpc-js\src\client-interceptors.ts:389:48)
at ~\<project_path>\node_modules\@grpc\grpc-js\src\call-stream.ts:276:24
at processTicksAndRejections (node:internal/process/task_queues:78:11)
[ERROR] 08:21:29 Error: 16 UNAUTHENTICATED: Failed to retrieve auth metadata with error: request to https://www.googleapis.com/oauth2/v4/token failed, reason: getaddrinfo ENOTFOUND www.googleapis.com
If this was a credentials issue, I should see this UNAUTHENTICATED error as soon as my server starts but this is hard to diagnose because it happens randomly after a set period of time. Has anyone encountered this type of error with Google Pubsub?
I do have a generated Credentials file that you can get from your google developer console for OAuth. It has the following keys
(type, project_id, private_key_id, private_key, client_email, client_id, auth_uri, token_uri, auth_provider_x509_cert_url, client_x509_cert_url).
I only use the project_id, private_key, client email. Do I need to use the others in order to stop this error from occuring? I think I linked directly to the credentials file before using an .env variable as per the google pubsub package docs and still got the same error. I know with Oauth, there is a refresh token timer of a couple of days and was wondering if that could be the cause of this. The refresh token isn't being picked up and therefore google apis cant authenticate. That's just a wild guess though. Any help would be much appreciated.
My code is below to access the service.
package.json
"@axelspringer/graphql-google-pubsub": "^2.1.0",
"googleapis": "^92.0.0",
"express": "^4.17.1",
"express-serve-static-core": "^0.1.1",
"cors": "^2.8.5",
"cookie-parser": "^1.4.5",
"apollo-server": "^3.5.0",
"apollo-server-core": "^3.5.0",
"apollo-server-express": "^3.5.0",
"graphql-tools": "^7.0.2",
"subscriptions-transport-ws": "^0.11.0",
src/index.ts
import { GooglePubSub } from "@axelspringer/graphql-google-pubsub";
const express = require("express");
const cookies = require("cookie-parser");
import cors from "cors";
import { createServer } from "http";
import { makeExecutableSchema } from "@graphql-tools/schema";
import { ApolloServer } from "apollo-server-express";
import {
ApolloServerPluginLandingPageGraphQLPlayground,
ApolloServerPluginLandingPageDisabled,
} from "apollo-server-core";
import {
ConnectionContext,
ConnectionParams,
SubscriptionServer,
} from "subscriptions-transport-ws";
const pubSubOptions = {projectId: <GOOGLE project_id>, credentials: {client_email: <GOOGLE client_email>, private_key: <GOOGLE private_key>} }
const pubsub = new GooglePubSub(pubSubOptions);
const context = async ({ req, res, connection }: MyContext) => {
const msgHeader = connection ? connection.context : req;
return {
req,
res,
pubsub,
};
};
(async function () {
const app = express();
app.use(cors());
const httpServer = createServer(app);
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
const server = new ApolloServer({
schema,
context,
plugins: [
process.env.NODE_ENV === "development"
? ApolloServerPluginLandingPageGraphQLPlayground()
: ApolloServerPluginLandingPageDisabled(),
{
async serverWillStart() {
return {
async drainServer() {
subscriptionServer.close();
},
};
},
},
],
});
const subscriptionServer = SubscriptionServer.create(
{
schema,
execute,
subscribe,
onConnect: (
connectionParams: ConnectionParams,
webSocket: WebSocket,
ConnectionContext: ConnectionContext
) => {
const context: any = {
pubsub,
};
return context;
},
},
{ server: httpServer, path: server.graphqlPath }
);
await server.start();
app.use(cookies());
server.applyMiddleware({ app });
const dbUri = db_url();
try {
await mongoose.connect(dbUri, configs.MONGO_OPTIONS);
} catch (err) {
if (err instanceof Error) {
throw new Error(err.message);
}
process.exit(1);
}
httpServer.listen(PORT, () =>
console.log(
` Server ready at ${configs.apiURL}:${PORT}${server.graphqlPath}`
)
);
})();