snipe / snipe-it

A free open source IT asset/license management system
https://snipeitapp.com
GNU Affero General Public License v3.0
11.01k stars 3.18k forks source link

On php upgrade.php - PHP Fatal error: Allowed memory size of 524288000 bytes exhausted (tried to allocate 20480 bytes) in /var/www/snipeit/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 368 #14206

Open fbouchard2 opened 8 months ago

fbouchard2 commented 8 months ago

Debug mode

Describe the bug

When trying to upgrade Snipe-it using either php upgrade.php or php artisan migrate,

during the "Migrating: 2023_01_21_225350_add_eol_date_on_assets_table"

I get an error message stating;

PHP Fatal error: Allowed memory size of 524288000 bytes exhausted (tried to allocate 20480 bytes) in /var/www/snipeit/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 375 PHP Fatal error: Allowed memory size of 524288000 bytes exhausted (tried to allocate 32768 bytes) in /var/www/snipeit/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php on line 1

I do have quite a large Assets table - (44495 total)

Reproduction steps

  1. Pull new files (git pull)
  2. php upgrade.php

Expected behavior

Database migration succeeds

Screenshots

No response

Snipe-IT Version

Newest - dpm

Operating System

Ubuntu

Web Server

Apache

PHP Version

PHP 7.4.3-4ubuntu2.19

Operating System

No response

Browser

No response

Version

No response

Device

No response

Operating System

No response

Browser

No response

Version

No response

Error messages

PHP Fatal error: Allowed memory size of 524288000 bytes exhausted (tried to allocate 20480 bytes) in /var/www/snipeit/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 375 PHP Fatal error: Allowed memory size of 524288000 bytes exhausted (tried to allocate 32768 bytes) in /var/www/snipeit/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php on line 1

Additional context

-Large-ish asset database, -~Asset table at 74 ish columns with custom fields -Table settings: image

snipe commented 8 months ago

45k assets is not really that large tho. We have customers with vastly larger asset tables. Usually when we see memory errors there’s some weird data that’s causing PHP to do weird recursive things.

fbouchard2 commented 8 months ago

Interesting. Also I Tried to set memory_limit to -1 (test server) but the upgrade message won't budge from 524288000 bytes, is this set manually in one of the files? I modified php.ini from the php --ini output

Anywhere I should look for this recursive data?

fbouchard2 commented 8 months ago

Update! So I debugged the migration and found it was crashing on a particular model->assets where there was 10k assets for the particular model.

I was able to successfully run the migration with ini_set('memory_limit', '-1'); in the "database\migrations\2023_01_21_225350_add_eol_date_on_assets_table.php"

` public function up() {

    Schema::table('assets', function (Blueprint $table) {

        if (!Schema::hasColumn('assets', 'asset_eol_date')) {
            $table->date('asset_eol_date')->after('purchase_date')->nullable()->default(null);
        }

        // This is a temporary shim so we don't have to modify the asset observer for migrations where
        // there is a large version difference. (See the AssetObserver notes). This column gets created
        // later in 2023_07_13_052204_denormalized_eol_and_add_column_for_explicit_date_to_assets.php
        // but we have to temporarily create it now so the save method below doesn't break
        if (!Schema::hasColumn('assets', 'eol_explicit')) {
            $table->boolean('eol_explicit')->default(false)->after('asset_eol_date');
        }
    });

    // Chunk the model query to get the models that do have an EOL date
    // We use saveQuietly() here to skip the AssetObserver, since it modifies fields
    // that do not yet exist on the assets table.
    AssetModel::whereNotNull('eol')->chunk(10, function ($models) { <---- Was failing in here 
        foreach ($models as $model) {
            foreach ($model->assets as $asset) {

                if ($asset->purchase_date!='') {
                    $asset->asset_eol_date = $asset->present()->eol_date();
                    $asset->saveQuietly();
                }

            }
        }
    });

}`

I can run the migration like this for now but is this something i'm going to have to do for each update?

Thanks!

snipe commented 8 months ago

If the migration completed, it shouldn't run again, no.