Infiniti loop in lifecycle method

System Information
  • strapi - 4.11.7:
  • macOS:
  • ** sqlite**:
  • ** node - v16.13.0**:
  • npm - 8.1.0:
  • yarn - 1.13.0:

I need to update user model in strapi admin panel and after press save button should check if some fields (e.g. bitcoin_total) is changed then it should change status field in the user model
when I trying run the code below I have Infiniti loop

'use strict';

module.exports = {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register(/*{ strapi }*/) {},

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  bootstrap({ strapi }) {
    strapi.db.lifecycles.subscribe({
      models: ["plugin::users-permissions.user"],
      beforeUpdate: async (event) => {
        const previousData = await strapi.entityService.findOne(
          "plugin::users-permissions.user",
          event.params.data.id,
          {
            fields: [
              "bitcoin_total",
              "ethereum_total",
              "litecoin_total",
              "dogecoin_total",
              "tetherTRC20_total",
              "tron_total",
              "status",
            ],
          },
        );

        if (previousData.bitcoin_total !== event.params.data.bitcoin_total) {
          await strapi.entityService.update('plugin::users-permissions.user', event.params.data.id, {
            data: {
              id: event.params.data.id,
              status: 'Gold',
            },
          })
        }
      },
    });
  },
};

please give me a hint

did this in another way instead using bootstrap function
extended behavior of the users-permission plugin
created
backend/src/extensions/users-permissions/strapi-server.js
and extended

module.exports = (plugin) => {
plugin.controllers.contentmanageruser.update = async (ctx) => {
// some logic with user statuses
  
const updatedUser = await strapi.entityService.update(
      'plugin::users-permissions.user',
      ctx.params.id,
      {
        data: {
          bitcoin_total,
          ethereum_total,
          litecoin_total,
          dogecoin_total,
          tetherTRC20_total,
          tron_total,
          status: newStatus,
          personal_deposit: personalContribution,
          structural_turnover
        },
      }
    );

    ctx.body = await sanitizeOutput(updatedUser, ctx);
  }

  return plugin;
}

the infinite loop error is gone
but I don`t figured out why this error occurred

A beforeUpdate hook should not update (via another entity service call) the same object that is about to be updated. That simply results in another call to the hook, which queues up yet another update … Ad infinitum.

I believe that what you should have done is update the params.data object that is passed into the lifecycle hook, to add or modify your status field. There’s an example here (Models | Strapi Documentation) that shows adding a discount by modifying the incoming params.data object.

2 Likes

Thank you very much for the explanation now i got it.

I’m solving an update inside an afterUpdate lifecycle function by running a timeOut function (to give a delay of 3 seconds after the update) and then retrieve (get) the entity again.

If the value in the entity is different than the new value I have → update
Else return