shapecode / cron-bundle

This bundle provides a simple interface for registering repeated scheduled tasks within your application.
https://shapecode.github.io/cron-bundle/
MIT License
56 stars 27 forks source link

Scan can't find new cron #44

Open Filoz opened 3 years ago

Filoz commented 3 years ago

Hi, I had a problem in Symfony 5.3 with the shapecode:cron:scan command because it couldn't find any CronJob.

I got deeper and I found that the problem was here: https://github.com/shapecode/cron-bundle/blob/master/src/EventListener/AnnotationJobLoaderListener.php#L40

Because of that https://symfony.com/blog/new-in-symfony-5-3-lazy-command-description

In my command I had a description like
class MyCommand extends Command { protected static $defaultDescription = '...';

and that was the problem!

With the description, the $this->application->all() return Symfony\Component\Console\Command\LazyCommand , instead of MyCommand class. Than the LazyCommand class is used as argument for the reflection in the next line $reflClass = new ReflectionClass($command);

Removing the description from MyCommand worked fine.

I hope that this little explanation could help someone when updating symfony

best regards

frostieDE commented 3 years ago

As a workaround, you may specify the command schedule inside your configuration using a dedicated tag as such:

App\Command\MyFancyCommand:
  tags:
    - { name: shapecode_cron.cron_job, expression: '@daily' }  

(see https://github.com/shapecode/cron-bundle/blob/master/src/DependencyInjection/Compiler/CronJobCompilerPass.php)

Unfortunately I am currently unable to verify whether this command is still considered lazy.

alessandro-podo commented 2 years ago

i want to use this Bundle with SF6

an possible Solution for that is, to use the new TaggedIterator(SF5.3) to get all Commands. What do you say?

nicklog commented 2 years ago

I'll take a look at it ;)

alessandro-podo commented 2 years ago

as a POC:

`class GetTaggedService { public function __construct(#[TaggedIterator('console.command')] private iterable $commands, private Reader $reader) { }

public function getCronJob(): array
{
    $job = [];
    foreach ($this->commands as $command) {
        $reflectionClass = new ReflectionClass($command);

        foreach ($this->reader->getClassAnnotations($reflectionClass) as $annotation) {
            if (!($annotation instanceof CronJob)) {
                continue;
            }
            $job[] = [
                'command' => $command,
                'annotation' => $annotation,
            ];
        }
        $job[] = $command;
    }

    return $job;
}

} `

c33s commented 2 years ago

my workaround:

Shapecode\Bundle\CronBundle\EventListener\AnnotationJobLoaderListener:

...
    public function onLoadJobs(LoadJobsEvent $event): void
    {
        foreach ($this->application->all() as $command) {
            if ($command instanceof LazyCommand) {
                $command = $command->getCommand();
            }
            // Check for an @CronJob annotation
            $reflectionClass = new ReflectionClass($command);

            foreach ($this->reader->getClassAnnotations($reflectionClass) as $annotation) {
                if (! ($annotation instanceof CronJob)) {
                    continue;
                }

                $arguments    = $annotation->arguments;
                $maxInstances = $annotation->maxInstances;
                $schedule     = $annotation->value;
                assert(is_string($schedule));

                $meta = CronJobMetadata::createByCommand($schedule, $command, $arguments, $maxInstances);
                $event->addJob($meta);
            }
        }
    }
...