App crashes randomly and doesn't recover (Heroku H10)

Feature(s) impacted

App general usage

Observed behavior

At some point of regular usage of the app, it crashes and all future requests will fail until we manually restart the app.
This happens since 1 or 2 months and doesn’t seem to be triggered by a specific action on our side. Just regular navigation in the app.

Expected behavior

The app is stable, if there are errors it recovers and doesn’t stay down.

Failure Logs

2022-05-30T07:31:26.907920+00:00 app[web.1]: OPTIONS /forest/catalogueEntity.csv?fields%5BcatalogueEntity%5D=catalogueEntityId%2Cname%2CshortName%2CcatalogueTarget%2Cprice%2Chours%2Cstatus%2Cpartner%2CnbTrainingEntity%2Cprogramme%2CrefTom%2CnbCaseStudy%2CtimeMail%2CtimeBiblio%2CtimeOffline%2CtimeVideoOffline%2CtimeCall%2CtimeVisio%2CtimeTutoring%2CappName%2CvisioRegistrationLink%2CrefProduct&page%5Bnumber%5D=1&page%5Bsize%5D=15&sort=-shortName&filename=parcours+du+catalogue&header=ID%2CNom%2CNom+court%2CMarch%C3%A9+cible%2CPrix+catalogue+%28HT%29%2CNb+d%27heures%2CStatut%2CPartenaire%2CNb+de+modules%2CProgramme%2CR%C3%A9f%C3%A9rence+sur+TOM%2CNb+de+mise%28s%29+en+situation%2C%23+Mail%2C%23+Biblio%2C%23+Prep+cas+pratique%2C%23+Vid%C3%A9o+hors+ligne%2C%23+Appel%2C%23+Visio%2C%23+Tutorat%2CNom+app%2CLien+classe+virtuelle%2CR%C3%A9f%C3%A9rence+produit&sessionToken=&timezone=Europe%2FParis 204 0 - 0.159 ms
2022-05-30T07:31:27.046670+00:00 app[web.1]: /app/node_modules/forest-express/node_modules/csv-stringify/lib/index.js:282
2022-05-30T07:31:27.046672+00:00 app[web.1]: containsdelimiter = field.indexOf(delimiter) >= 0;
2022-05-30T07:31:27.046675+00:00 app[web.1]: ^
2022-05-30T07:31:27.046675+00:00 app[web.1]: 
2022-05-30T07:31:27.046675+00:00 app[web.1]: TypeError: field.indexOf is not a function
2022-05-30T07:31:27.046676+00:00 app[web.1]: at Stringifier.stringify (/app/node_modules/forest-express/node_modules/csv-stringify/lib/index.js:282:35)
2022-05-30T07:31:27.046676+00:00 app[web.1]: at Stringifier.write (/app/node_modules/forest-express/node_modules/csv-stringify/lib/index.js:211:20)
2022-05-30T07:31:27.046677+00:00 app[web.1]: at /app/node_modules/forest-express/node_modules/csv-stringify/lib/index.js:45:21
2022-05-30T07:31:27.046677+00:00 app[web.1]: at processTicksAndRejections (node:internal/process/task_queues:78:11)
2022-05-30T07:31:27.053324+00:00 heroku[router]: sock=backend at=error code=H18 desc="Server Request Interrupted" method=GET path="/forest/catalogueEntity.csv?fields%5BcatalogueEntity%5D=catalogueEntityId%2Cname%2CshortName%2CcatalogueTarget%2Cprice%2Chours%2Cstatus%2Cpartner%2CnbTrainingEntity%2Cprogramme%2CrefTom%2CnbCaseStudy%2CtimeMail%2CtimeBiblio%2CtimeOffline%2CtimeVideoOffline%2CtimeCall%2CtimeVisio%2CtimeTutoring%2CappName%2CvisioRegistrationLink%2CrefProduct&page%5Bnumber%5D=1&page%5Bsize%5D=15&sort=-shortName&filename=parcours+du+catalogue&header=ID%2CNom%2CNom+court%2CMarch%C3%A9+cible%2CPrix+catalogue+%28HT%29%2CNb+d%27heures%2CStatut%2CPartenaire%2CNb+de+modules%2CProgramme%2CR%C3%A9f%C3%A9rence+sur+TOM%2CNb+de+mise%28s%29+en+situation%2C%23+Mail%2C%23+Biblio%2C%23+Prep+cas+pratique%2C%23+Vid%C3%A9o+hors+ligne%2C%23+Appel%2C%23+Visio%2C%23+Tutorat%2CNom+app%2CLien+classe+virtuelle%2CR%C3%A9f%C3%A9rence+produit&sessionToken=&timezone=Europe%2FParis" host=forest-backend-edumiam.herokuapp.com request_id=2f1c8714-9fac-43fd-8f35-d29e48ef5866 fwd="91.200.205.90" dyno=web.1 connect=0ms service=56ms status=503 bytes= protocol=https
2022-05-30T07:31:27.177989+00:00 heroku[web.1]: Process exited with status 1
2022-05-30T07:31:27.224021+00:00 heroku[web.1]: State changed from up to crashed
2022-05-30T07:31:37.928389+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=OPTIONS path="/forest/catalogueItem.csv?fields%5BcatalogueEntity%5D=catalogueEntityId%2Cname%2CshortName%2CcatalogueTarget%2Cprice%2Chours%2Cstatus%2Cpartner%2CnbTrainingEntity%2Cprogramme%2CrefTom%2CnbCaseStudy%2CtimeMail%2CtimeBiblio%2CtimeOffline%2CtimeVideoOffline%2CtimeCall%2CtimeVisio%2CtimeTutoring%2CappName%2CvisioRegistrationLink%2CrefProduct&page%5Bnumber%5D=1&page%5Bsize%5D=15&sort=-shortName&filename=parcours+par+apprenant&header=ID%2CNom%2CNom+court%2CMarch%C3%A9+cible%2CPrix+catalogue+%28HT%29%2CNb+d%27heures%2CStatut%2CPartenaire%2CNb+de+modules%2CProgramme%2CR%C3%A9f%C3%A9rence+sur+TOM%2CNb+de+mise%28s%29+en+situation%2C%23+Mail%2C%23+Biblio%2C%23+Prep+cas+pratique%2C%23+Vid%C3%A9o+hors+ligne%2C%23+Appel%2C%23+Visio%2C%23+Tutorat%2CNom+app%2CLien+classe+virtuelle%2CR%C3%A9f%C3%A9rence+produit&sessionToken=&timezone=Europe%2FParis" host=forest-backend-edumiam.herokuapp.com request_id=16406aeb-18f3-4e42-9819-40d0d392c6eb fwd="91.200.205.90" dyno= connect= service= status=503 bytes= protocol=https

Context

  • Project name: forest backend
  • Team name: Edumiam
  • Environment name: NodeJS
  • Agent type & version: “forest-express-sequelize”: “^8.5.3”,

Hello @alexphiev,

This error seems to be triggered by a CSV export of your collection catalogueEntity. Are you able to reproduce it?

Actually yes, it happens consistently when we export from catalogueEntity at least.
We don’t control the export function, so could it be an issue on your side?

Hi @alexphiev ,

May I have your model for the collection where it crash ?

Hi @shohanr,

Sure!

const CatalogueEntity = sequelize.define(
    "catalogueEntity",
    {
      catalogueEntityId: {
        type: DataTypes.INTEGER,
        field: "catalogue_entity_id",
        primaryKey: true,
        defaultValue: Sequelize.literal(
          "nextval('catalogue_entity_catalogue_entity_id_seq'::regclass)"
        ),
        allowNull: false,
      },
      name: {
        type: DataTypes.STRING,
      },
      createdDate: {
        type: DataTypes.DATE,
        field: "created_date",
        defaultValue: Sequelize.literal("now()"),
        allowNull: false,
      },
      price: {
        type: DataTypes.DOUBLE,
      },
      hours: {
        type: DataTypes.DOUBLE,
      },
      refProduct: {
        type: DataTypes.STRING,
        field: "ref_product",
      },
      refIperia: {
        type: DataTypes.STRING,
        field: "ref_iperia",
      },
      refIperiaOld: {
        type: DataTypes.STRING,
        field: "ref_iperia_old",
      },
      catalogueTarget: {
        type: DataTypes.STRING,
        field: "catalogue_target",
      },
      refTom: {
        type: DataTypes.STRING,
        field: "ref_tom",
      },
      status: {
        type: DataTypes.STRING,
      },
      launchDate: {
        type: DataTypes.DATE,
        field: "launch_date",
      },
      partner: {
        type: DataTypes.STRING,
      },
      nbTrainingEntity: {
        type: DataTypes.INTEGER,
        field: "nb_training_entity",
      },
      visioRegistrationLink: {
        type: DataTypes.STRING,
        field: "visio_registration_link",
      },
      nbCaseStudy: {
        type: DataTypes.INTEGER,
        field: "nb_case_study",
      },
      timeMail: {
        type: DataTypes.DOUBLE,
        field: "time_mail",
      },
      timeCall: {
        type: DataTypes.DOUBLE,
        field: "time_call",
      },
      timeTutoring: {
        type: DataTypes.DOUBLE,
        field: "time_tutoring",
      },
      timeOffline: {
        type: DataTypes.DOUBLE,
        field: "time_offline",
      },
      timeBiblio: {
        type: DataTypes.DOUBLE,
        field: "time_biblio",
      },
      timeVideoOffline: {
        type: DataTypes.DOUBLE,
        field: "time_video_offline",
      },
      timeChatOnline: {
        type: DataTypes.DOUBLE,
        field: "time_chat_online",
      },
      timeVisio: {
        type: DataTypes.DOUBLE,
        field: "time_visio",
      },
      programme: {
        type: DataTypes.STRING,
      },
      idQuickbooks: {
        type: DataTypes.STRING,
        field: "id_quickbooks",
      },
      shortName: {
        type: DataTypes.STRING,
        field: "short_name",
      },
      appName: {
        type: DataTypes.STRING,
        field: "app_name",
      },
      z1: {
        type: DataTypes.STRING,
      },
      z2: {
        type: DataTypes.STRING,
      },
      z3: {
        type: DataTypes.STRING,
      },
      z4: {
        type: DataTypes.STRING,
      },
      z5: {
        type: DataTypes.STRING,
      },
      z6: {
        type: DataTypes.STRING,
      },
      z7: {
        type: DataTypes.STRING,
      },
      z8: {
        type: DataTypes.STRING,
      },
      z9: {
        type: DataTypes.STRING,
      },
      z10: {
        type: DataTypes.STRING,
      },
      z11: {
        type: DataTypes.STRING,
      },
      z12: {
        type: DataTypes.STRING,
      },
      z13: {
        type: DataTypes.STRING,
      },
      z14: {
        type: DataTypes.STRING,
      },
      z15: {
        type: DataTypes.STRING,
      },
      z16: {
        type: DataTypes.STRING,
      },
      z17: {
        type: DataTypes.STRING,
      },
      z18: {
        type: DataTypes.STRING,
      },
      z19: {
        type: DataTypes.STRING,
      },
      z20: {
        type: DataTypes.STRING,
      },
    },
    {
      tableName: "catalogue_entity",
      timestamps: false,
      schema: process.env.DATABASE_SCHEMA,
    }
  );

  // This section contains the relationships for this model. See: https://docs.forestadmin.com/documentation/v/v6/reference-guide/relationships#adding-relationships.
  CatalogueEntity.associate = (models) => {
    CatalogueEntity.hasMany(models.quoteInvoice, {
      foreignKey: {
        name: "catalogueEntityIdKey",
        field: "catalogue_entity_id",
      },
      sourceKey: "catalogueEntityId",
      as: "catalogueEntityQuoteInvoices",
    });
    CatalogueEntity.hasMany(models.catalogueItem, {
      foreignKey: {
        name: "catalogueEntityIdKey",
        field: "catalogue_entity_id",
      },
      sourceKey: "catalogueEntityId",
      as: "catalogueEntityCatalogueItems",
    });
    CatalogueEntity.hasMany(models.catalogueTrainingEntity, {
      foreignKey: {
        name: "catalogueEntityIdKey",
        field: "catalogue_entity_id",
      },
      sourceKey: "catalogueEntityId",
      as: "catalogueEntityCatalogueTrainingEntities",
    });
  };

1 Like

Hi,
I do not see anything special in your model. Do you have some smart fields that I could look into ?

Hi @shohanr !

I removed one smart field that wasn’t used anymore and it seems that it works without crashes now.

Here it is. Is there something wrong with the way it was written?

{
      field: 'nbTrainingEntity',
      type: 'Number',
      get: async (catalogueEntity) => {
        const existing = catalogueEntity.nbTrainingEntity;
        if (existing && existing !== 0) {
          return existing;
        } else {
          const sqlCommand = `SELECT COUNT(*)
                              FROM catalogue_training_entity
                              WHERE catalogue_training_entity.catalogue_entity_id = ${catalogueEntity.catalogueEntityId}`;
          const nbTrainingEntity = await sequelize.query(sqlCommand, {type: QueryTypes.SELECT});
          return nbTrainingEntity || 0;
        }
      },
      set: (catalogueEntity, nbTrainingEntity) => {
        catalogueEntity.nbTrainingEntity = nbTrainingEntity;
        return catalogueEntity;
      }
    }

Hi @alexphiev ,

Glad that it works now !
It might was a probable issue but I would need to go deeper into your project, but it may not be useful now that the issue is resolved.

Good day,

Shohan