vendure-ecommerce / vendure-docker-compose

A containerized Vendure server and storefront
MIT License
33 stars 37 forks source link

Worker startup: QueryFailedError: relation "administrator" does not exist #8

Closed ddanielgal closed 2 years ago

ddanielgal commented 2 years ago

I am trying to run the worker container part of this containerized example in kubernetes, in production mode. The database in question is a brand new empty postgres database launched from the postgres:11 docker image.

I am using the latest Vendure version (1.3.2)

The full error message in the worker's log:

warn 11/7/21, 7:47 PM - [Vendure Worker] Awaiting DB schema creation... (attempt 18)
error 11/7/21, 7:47 PM - [TypeORM] Query error: SELECT "Administrator"."createdAt" AS "Administrator_createdAt", "Administrator"."updatedAt" AS "Administrator_updatedAt", "Administrator"."deletedAt" AS "Administrator_deletedAt", "Administrator"."firstName" AS "Administrator_firstName", "Administrator"."lastName" AS "Administrator_lastName", "Administrator"."emailAddress" AS "Administrator_emailAddress", "Administrator"."id" AS "Administrator_id", "Administrator"."userId" AS "Administrator_userId" FROM "administrator" "Administrator"
error 11/7/21, 7:47 PM - [Vendure Worker] Timed out when awaiting the DB schema to be ready!
QueryFailedError: relation "administrator" does not exist
    at new QueryFailedError (/usr/src/litera-admin/node_modules/typeorm/error/QueryFailedError.js:11:28)
    at PostgresQueryRunner.<anonymous> (/usr/src/litera-admin/node_modules/typeorm/driver/postgres/PostgresQueryRunner.js:247:31)
    at step (/usr/src/litera-admin/node_modules/typeorm/node_modules/tslib/tslib.js:141:27)
    at Object.throw (/usr/src/litera-admin/node_modules/typeorm/node_modules/tslib/tslib.js:122:57)
    at rejected (/usr/src/litera-admin/node_modules/typeorm/node_modules/tslib/tslib.js:113:69)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
error 11/7/21, 7:47 PM - [TypeORM] Query error: SELECT "Zone"."createdAt" AS "Zone_createdAt", "Zone"."updatedAt" AS "Zone_updatedAt", "Zone"."name" AS "Zone_name", "Zone"."id" AS "Zone_id", "Zone__members"."createdAt" AS "Zone__members_createdAt", "Zone__members"."updatedAt" AS "Zone__members_updatedAt", "Zone__members"."code" AS "Zone__members_code", "Zone__members"."enabled" AS "Zone__members_enabled", "Zone__members"."id" AS "Zone__members_id", "Zone__members_translations"."createdAt" AS "Zone__members_translations_createdAt", "Zone__members_translations"."updatedAt" AS "Zone__members_translations_updatedAt", "Zone__members_translations"."languageCode" AS "Zone__members_translations_languageCode", "Zone__members_translations"."name" AS "Zone__members_translations_name", "Zone__members_translations"."id" AS "Zone__members_translations_id", "Zone__members_translations"."baseId" AS "Zone__members_translations_baseId" FROM "zone" "Zone" LEFT JOIN "zone_members_country" "Zone_Zone__members" ON "Zone_Zone__members"."zoneId"="Zone"."id" LEFT JOIN "country" "Zone__members" ON "Zone__members"."id"="Zone_Zone__members"."countryId"  LEFT JOIN "country_translation" "Zone__members_translations" ON "Zone__members_translations"."baseId"="Zone__members"."id"
QueryFailedError: relation "zone" does not exist
    at new QueryFailedError (/usr/src/litera-admin/node_modules/typeorm/error/QueryFailedError.js:11:28)
    at PostgresQueryRunner.<anonymous> (/usr/src/litera-admin/node_modules/typeorm/driver/postgres/PostgresQueryRunner.js:247:31)
    at step (/usr/src/litera-admin/node_modules/typeorm/node_modules/tslib/tslib.js:141:27)
    at Object.throw (/usr/src/litera-admin/node_modules/typeorm/node_modules/tslib/tslib.js:122:57)
    at rejected (/usr/src/litera-admin/node_modules/typeorm/node_modules/tslib/tslib.js:113:69)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  length: 104,
  severity: 'ERROR',
  code: '42P01',
  detail: undefined,
  hint: undefined,
  position: '890',
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'parse_relation.c',
  line: '1180',
  routine: 'parserOpenTable',
  query: 'SELECT "Zone"."createdAt" AS "Zone_createdAt", "Zone"."updatedAt" AS "Zone_updatedAt", "Zone"."name" AS "Zone_name", "Zone"."id" AS "Zone_id", "Zone__members"."createdAt" AS "Zone__members_createdAt", "Zone__members"."updatedAt" AS "Zone__members_updatedAt", "Zone__members"."code" AS "Zone__members_code", "Zone__members"."enabled" AS "Zone__members_enabled", "Zone__members"."id" AS "Zone__members_id", "Zone__members_translations"."createdAt" AS "Zone__members_translations_createdAt", "Zone__members_translations"."updatedAt" AS "Zone__members_translations_updatedAt", "Zone__members_translations"."languageCode" AS "Zone__members_translations_languageCode", "Zone__members_translations"."name" AS "Zone__members_translations_name", "Zone__members_translations"."id" AS "Zone__members_translations_id", "Zone__members_translations"."baseId" AS "Zone__members_translations_baseId" FROM "zone" "Zone" LEFT JOIN "zone_members_country" "Zone_Zone__members" ON "Zone_Zone__members"."zoneId"="Zone"."id" LEFT JOIN "country" "Zone__members" ON "Zone__members"."id"="Zone_Zone__members"."countryId"  LEFT JOIN "country_translation" "Zone__members_translations" ON "Zone__members_translations"."baseId"="Zone__members"."id"',
  parameters: []
}

Did I miss something during the setup or is this some kind of internal error?

My full config:

import {
  dummyPaymentHandler,
  DefaultJobQueuePlugin,
  DefaultSearchPlugin,
  VendureConfig,
} from "@vendure/core";
import { defaultEmailHandlers, EmailPlugin } from "@vendure/email-plugin";
import { AssetServerPlugin } from "@vendure/asset-server-plugin";
import { AdminUiPlugin } from "@vendure/admin-ui-plugin";
import path from "path";

const isProd = process.env.NODE_ENV === "production";

export const config: VendureConfig = {
  apiOptions: {
    port: Number(process.env.ADMIN_API_PORT),
    adminApiPath: "admin-api",
    adminApiPlayground: isProd
      ? {}
      : {
          settings: {
            "request.credentials": "include",
          } as any,
        }, // turn this off for production
    adminApiDebug: !isProd, // turn this off for production
    shopApiPath: "shop-api",
    shopApiPlayground: isProd
      ? {}
      : {
          settings: {
            "request.credentials": "include",
          } as any,
        }, // turn this off for production
    shopApiDebug: !isProd, // turn this off for production
  },
  authOptions: {
    superadminCredentials: {
      identifier: String(process.env.ADMIN_SUPERADMIN_USERNAME),
      password: String(process.env.ADMIN_SUPERADMIN_PASSWORD),
    },
  },
  dbConnectionOptions: {
    type: "postgres",
    synchronize: !isProd, // turn this off for production
    logging: Boolean(process.env.ADMIN_DB_LOGGING),
    database: String(process.env.DB_DATABASE),
    host: String(process.env.DB_HOSTNAME),
    port: Number(process.env.DB_PORT),
    username: String(process.env.DB_USERNAME),
    password: String(process.env.DB_PASSWORD),
    migrations: [path.join(__dirname, "../migrations/*.ts")],
  },
  paymentOptions: {
    paymentMethodHandlers: [dummyPaymentHandler],
  },
  customFields: {},
  plugins: [
    AssetServerPlugin.init({
      route: "assets",
      assetUploadDir: path.join(__dirname, "../static/assets"),
    }),
    DefaultJobQueuePlugin,
    DefaultSearchPlugin,
    EmailPlugin.init({
      devMode: true,
      outputPath: path.join(__dirname, "../static/email/test-emails"),
      route: "mailbox",
      handlers: defaultEmailHandlers,
      templatePath: path.join(__dirname, "../static/email/templates"),
      globalTemplateVars: {
        // The following variables will change depending on your storefront implementation
        fromAddress: '"example" <noreply@example.com>',
        verifyEmailAddressUrl: "http://localhost:8080/verify",
        passwordResetUrl: "http://localhost:8080/password-reset",
        changeEmailAddressUrl:
          "http://localhost:8080/verify-email-address-change",
      },
    }),
    AdminUiPlugin.init({
      route: "admin",
      port: Number(process.env.ADMIN_UI_PORT),
    }),
  ],
};
michaelbromley commented 2 years ago

Hi, Did you already have the database created in postgres? Vendure will not create the database if it does not exist already.

ddanielgal commented 2 years ago

Yes, listing the databases in the postgres container gives me the following:

vendure=# \l
                              List of databases
   Name    | Owner  | Encoding |  Collate   |   Ctype    | Access privileges
-----------+--------+----------+------------+------------+-------------------
 postgres  | litera | UTF8     | en_US.utf8 | en_US.utf8 |
 template0 | litera | UTF8     | en_US.utf8 | en_US.utf8 | =c/litera        +
           |        |          |            |            | litera=CTc/litera
 template1 | litera | UTF8     | en_US.utf8 | en_US.utf8 | =c/litera        +
           |        |          |            |            | litera=CTc/litera
 vendure   | litera | UTF8     | en_US.utf8 | en_US.utf8 |
(4 rows)

In the worker container, DB_DATABASE env var is set to vendure.

michaelbromley commented 2 years ago

OK. And what's the value of process.env.NODE_ENV at runtime?

ddanielgal commented 2 years ago

NODE_ENV=production

michaelbromley commented 2 years ago

OK, I think that is the reason. This config line:

synchronize: !isProd, // turn this off for production

means that the DB structure will not be synchronized when in prod mode, which is why none of the tables are being created.

ddanielgal commented 2 years ago

You were right. Setting NODE_ENV=development for an initial run did start up the worker successfully. After this initial run, I stopped the worker, set NODE_ENV=production again and it started without errors this time.

Thank you for your help!