feathers icon indicating copy to clipboard operation
feathers copied to clipboard

@feathersjs/authentication-local times out on database error causing 502 bad gateway

Open MichaelJCole opened this issue 6 years ago • 1 comments

Steps to reproduce

Hi, my database connection was misconfigured in production.

info: Feathers application started on http://localhost:3001
(node:14124) UnhandledPromiseRejectionWarning: Error: connect ECONNREFUSED 127.0.0.1:27017
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1097:14)
(node:14124) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14124) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

This causes the authentication-local package to be unable to verify the user:

@feathersjs/authentication-local:verify Checking credentials [email protected] asdf

Unfortunately, when this method fails, it doesn't reply 500 or 401, it appears to not respond before the connection timeout.

This causes a "failed" in the browser's XHR request, and "502 Bad Gateway" coming out of Kubernetes using Traefik.

In my dev env, I started the app w/o a mongo and got the same results. I started mongo after feathers so the app could attempt to reconnect, but it didn't.

Expected behavior

If the service can't connect to the database, return a 500 instead of not responding before the timeout. This will prevent needing to debug 502 errors.

If the service can't reconnect if the database connection has failed, throw a fatal error.

Mongo not being able to connect to the DB should be a fatal error. This may be the default behavior, I'm using this error handling code in app.js:

const express = require('@feathersjs/express');
const Sentry = require('@sentry/node');
...
app.use(Sentry.Handlers.errorHandler());
app.use(express.errorHandler({ logger }));

Actual behavior

A 502 error is created at the gateway because Feathers is not responding before the connection times out.

System configuration

Tell us about the applicable parts of your setup.

Module versions (especially the part that's not working):

    "@feathersjs/authentication": "^2.1.16",
    "@feathersjs/authentication-jwt": "^2.0.10",
    "@feathersjs/authentication-local": "^1.2.9",
    "@feathersjs/configuration": "^2.0.6",
    "@feathersjs/errors": "^3.3.6",
    "@feathersjs/express": "^1.3.1",
    "@feathersjs/feathers": "^3.3.1",
    "@feathersjs/socketio": "^3.2.9",
    "@sentry/node": "^5.4.0"

NodeJS version: 10 Operating System: Linux

MichaelJCole avatar Jun 03 '19 16:06 MichaelJCole

Looks like the code is here? https://github.com/feathersjs/feathers/blob/buzzard/packages/authentication-local/lib/verifier.js#L85

I get the same behavior w/o Sentry as an error handler...

This catch() is a workaround to put the Docker Container into a CrashLoop in Kubernetes. That way, it's visible as unhealthy - fail faster.

const mongoose = require('mongoose');

module.exports = function(app) {
  mongoose.connect(app.get('mongodb'), {
    useCreateIndex: true,
    useNewUrlParser: true
  }).catch(err => {
    console.log(err);
    process.exit(1);
  });
  mongoose.Promise = global.Promise;

  app.set('mongooseClient', mongoose);
};

MichaelJCole avatar Jun 03 '19 16:06 MichaelJCole

I'd say the best way to solve this would be to catch misconfigurations on startup which in the upcoming version can be handled with configuration validation on startup and application setup hooks.

daffl avatar Oct 18 '22 23:10 daffl