Repository: strapi/strapi
File: packages/core/content-manager/server/src/history/services/lifecycles.ts (TypeScript)

Code before:
          // when the transaction has already been committed
          onCommit(async () => {
            for (const entry of localeEntries) {
              const status = await serviceUtils.getVersionStatus(uid, entry);

              await getService(strapi, 'history').createVersion({
                contentType: uid,
                data: omit(FIELDS_TO_IGNORE, entry) as Modules.Documents.AnyDocument,
                relatedDocumentId: documentId,
                locale: entry.locale,
                status,
                ...schemas,
              });
            }
          });
        });

        return result;
      });

      // Schedule a job to delete expired history versions every day at midnight
      strapi.cron.add({
        deleteHistoryDaily: {
          async task() {
            const BATCH_SIZE = 1000;

            try {
              const retentionDaysInMilliseconds =
                serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1000;
              const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);

              // Delete in batches of 1000 to avoid a single query that
              // exhausts the DB connection pool and blocks other operations.
              let deleted: number;
              do {
                // Fetch up to BATCH_SIZE expired IDs
                const expiredVersions = await strapi.db.query(HISTORY_VERSION_UID).findMany({
                  select: ['id'],
                  where: {
                    created_at: {
                      $lt: expirationDate,
                    },
                  },
                  limit: BATCH_SIZE,
                });

                const ids = expiredVersions.map((v: { id: number | string }) => v.id);
                deleted = ids.length;

                // Delete this batch by ID
                if (deleted > 0) {

Review comment (suggestion):
It looks like we're now logging errors twice because these are already caught at a higher level. I think you can remove the try/catches in this block

Code after:
          // when the transaction has already been committed
          onCommit(async () => {
            for (const entry of localeEntries) {
              const status = await serviceUtils.getVersionStatus(uid, entry);

              await getService(strapi, 'history').createVersion({
                contentType: uid,
                data: omit(FIELDS_TO_IGNORE, entry) as Modules.Documents.AnyDocument,
                relatedDocumentId: documentId,
                locale: entry.locale,
                status,
                ...schemas,
              });
            }
          });
        });

        return result;
      });

      // Schedule a job to delete expired history versions every day at midnight
      strapi.cron.add({
        deleteHistoryDaily: {
          async task() {
            const BATCH_SIZE = 1000;

            const retentionDaysInMilliseconds =
              serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1000;
            const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);

            // Delete in batches of 1000 to avoid a single query that
            // exhausts the DB connection pool and blocks other operations.
            let deleted: number;
            do {
              // Fetch up to BATCH_SIZE expired IDs
              const expiredVersions = await strapi.db.query(HISTORY_VERSION_UID).findMany({
                select: ['id'],
                where: {
                  created_at: {
                    $lt: expirationDate,
                  },
                },
                limit: BATCH_SIZE,
              });

              const ids = expiredVersions.map((v: { id: number | string }) => v.id);
              deleted = ids.length;

              // Delete this batch by ID
              if (deleted > 0) {
                await strapi.db.query(HISTORY_VERSION_UID).deleteMany({