nunomaduro / laravel-console-task

✅ Laravel Console Task is a output method for Laravel Console Commands.
MIT License
254 stars 21 forks source link

Possible memory leak when throwing from task #13

Open sergejostir opened 4 years ago

sergejostir commented 4 years ago

Hello.

There seems to be memory leak when you throw an exception from within a task. I'm not entirely sure that this is even caused by this package, or it is consiquence of Laravel macro.

<?php // Some service class

use LaravelZero\Framework\Commands\Command;

class Class {
    public function method(Command $command)
    {
        $command->task('test', function() {
            throw new Exception();
        });
    }
}
class TestCommand {
    /**
     * Execute the console command.
     */
    public function handle()
        try {
            resolve(Class::class)->method($this);
        } catch (\Throwable $th) {
            //
        }
    }
}

The "Class" won't get destroyed even after there are no usable references to it anymore. If you have a command, that does a lot of tasks that might throw in some circumstances, but you catch exceptions and move on, you will end up with a lot of live instances that should actually already be garbage collected. I stumbled against this situation because I remove some files in a destructor, and it is only called jsut before the whole process completely exists, when it should already be called much earlier.

I have found this solution to the problem:

class Class {
    public function method(Command $command)
    {
        try {
            $command->task('test', function() {
                throw new Exception();
            });
        } catch (\Throwable $th) {
           throw new Exception();
        }
    }
}

The important thing is that we throw a NEW exception outside task. If you only throw the exception that you just caught, the problem persists. When you do this, the instance will be properly destroyed right after it's finished executing.

PS: The instance is also destroyed, if you run a NEW instance of the same class. It is destroyed just after the line that threw the previous exception is called.

sergejostir commented 4 years ago

I tried various things to get around this, but no luck so far. It seems to be a PHP related thing because I extracted the method from macro and the issue is the same.