2

I am trying to deploy my NestJS REST API on Heroku but I always get the following error:

 Web process failed to bind to $PORT within 60 seconds of launch

My configuration is pretty straight forward:

  1. In my main.ts I start my server with:

    await app.listen(process.env.PORT || AppModule.port);

  2. I added a Procfile in the root directory of my project which contains:

    web: npm run start:prod

  3. My package.json files contains these scripts:

    "build": "tsc -p tsconfig.build.json", "prestart:prod": "rimraf dist && npm run build", "start:prod": "node dist/main.js",

The process on Heroku builds succesfully, prints out these seamingly reassuring lines:

TypeOrmModule dependencies initialized
SharedModule dependencies initialized
AppModule dependencies initialized

But then immediately crashes with:

Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch

I use .env configuration across my application but I removed all HOST and PORT variables (and code references), so I have no clue what could be the cause of this error. Am I missing something?

EDIT I am hereby sharing my app.module and main.ts files:

app.module.ts

@Module({
  imports: [
    SharedModule,
    TypeOrmModule.forRootAsync({
      imports: [SharedModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        type: 'postgres',
        host: configService.getString('POSTGRES_HOST'),
        port: configService.getNumber('POSTGRES_DB_PORT'),
        username: configService.getString('POSTGRES_USER'),
        password: configService.getString('POSTGRES_PASSWORD'),
        database: configService.getString('POSTGRES_DB'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'],
      } as PostgresConnectionOptions),
    }),
    UserModule,
  ],
  controllers: [
    AppController,
  ],
  providers: [
    AppService,
  ],
})
export class AppModule {
  static port: number;
  static isDev: boolean;

  constructor(configurationService: ConfigService) {
    console.log(process.env.PORT);
    AppModule.port = configurationService.getNumber('PORT');
    AppModule.isDev = configurationService.getBoolean('ISDEV');
  }
}

My configuration.service.ts is a simple utility that reads from .env files:

import * as dotenv from 'dotenv';
import * as path from 'path';

@Injectable()
export class ConfigService {
  constructor() {
      const filePath = path.resolve('.env');
      dotenv.config({
      path: filePath,
    });
  }

  getNumber(key: string): number | undefined {
    return +process.env[key] as number | undefined;
  }

  getBoolean(key: string): boolean {
    return process.env[key] === 'true';
  }

  getString(key: string): string | undefined {
    return process.env[key];
  }
}

And finally my main.ts file:

async function bootstrap() {
  console.log(process.env.PORT);
  const app = await NestFactory.create(AppModule);
  app.enableCors();
  app.useGlobalPipes(new ValidationPipe(), new TimeStampPipe());
  app.use(json({ limit: '5mb' }));

  app.setGlobalPrefix('api/v1');
  await app.listen(process.env.PORT || AppModule.port);
}
bootstrap();

Could it be that my configuration.service.ts is interfering with heroku's env file?

Aaron Ullal
  • 4,855
  • 8
  • 35
  • 63

2 Answers2

3

If you are using fastify instead express as your platform, you need to define the host to 0.0.0.0 explicitly like this :

const port = process.env.PORT || AppModule.port;
const host = '0.0.0.0';
await app.listen(port, host);

This problem is caused by the fastify library. See the related discussion here: Fastify with Heroku.

1

Just as a summary, be careful on the database connection timeout that could lead to a global timeout of the heroku bootstrap as describe above

Adrien De Peretti
  • 3,342
  • 16
  • 22