Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 105
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
OnContinuouslyCommand
0.00% covered (danger)
0.00%
0 / 105
0.00% covered (danger)
0.00%
0 / 4
90
0.00% covered (danger)
0.00%
0 / 1
 getAllowedAppEnvs
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 handle
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 1
2
 daily
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
42
 getTimeOnlyDiffSeconds
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Olz\Command;
4
5use Olz\Command\Common\OlzCommand;
6use Olz\Entity\Throttling;
7use Symfony\Component\Console\Attribute\AsCommand;
8use Symfony\Component\Console\Command\Command;
9use Symfony\Component\Console\Input\ArrayInput;
10use Symfony\Component\Console\Input\InputInterface;
11use Symfony\Component\Console\Output\OutputInterface;
12
13#[AsCommand(name: 'olz:on-continuously')]
14class OnContinuouslyCommand extends OlzCommand {
15    /** @return array<string> */
16    protected function getAllowedAppEnvs(): array {
17        return ['dev', 'test', 'staging', 'prod'];
18    }
19
20    protected function handle(InputInterface $input, OutputInterface $output): int {
21        set_time_limit(4000);
22        ignore_user_abort(true);
23
24        $this->logAndOutput("Running continuously...", level: 'debug');
25        $throttling_repo = $this->entityManager()->getRepository(Throttling::class);
26        $throttling_repo->recordOccurrenceOf('on_continuously', $this->dateUtils()->getIsoNow());
27
28        $this->logAndOutput("Continuously processing email...", level: 'debug');
29        $this->symfonyUtils()->callCommand(
30            'olz:process-email',
31            new ArrayInput([]),
32            $output,
33        );
34
35        $this->daily('01:00:00', 'clean-temp-directory', function () use ($output) {
36            $this->symfonyUtils()->callCommand(
37                'olz:clean-temp-directory',
38                new ArrayInput([]),
39                $output,
40            );
41        });
42        $this->daily('01:05:00', 'clean-temp-database', function () use ($output) {
43            $this->symfonyUtils()->callCommand(
44                'olz:clean-temp-database',
45                new ArrayInput([]),
46                $output,
47            );
48        });
49        $this->daily('01:10:00', 'clean-logs', function () use ($output) {
50            $this->symfonyUtils()->callCommand(
51                'olz:clean-logs',
52                new ArrayInput([]),
53                $output,
54            );
55        });
56        $this->daily('01:15:00', 'send-telegram-configuration', function () use ($output) {
57            $this->symfonyUtils()->callCommand(
58                'olz:send-telegram-configuration',
59                new ArrayInput([]),
60                $output,
61            );
62        });
63        $this->daily('01:20:00', 'sync-solv', function () use ($output) {
64            $this->symfonyUtils()->callCommand(
65                'olz:sync-solv',
66                new ArrayInput([]),
67                $output,
68            );
69        });
70
71        // TODO: Remove this again!
72        $this->daily('01:25:00', 'send-test-email', function () use ($output) {
73            $this->symfonyUtils()->callCommand(
74                'olz:send-test-email',
75                new ArrayInput([]),
76                $output,
77            );
78        });
79
80        $this->daily('16:27:00', 'send-daily-notifications', function () use ($output) {
81            $this->symfonyUtils()->callCommand(
82                'olz:send-daily-notifications',
83                new ArrayInput([]),
84                $output,
85            );
86        });
87
88        $this->logAndOutput("Stopping workers...", level: 'debug');
89        $this->symfonyUtils()->callCommand(
90            'messenger:stop-workers',
91            new ArrayInput([]),
92            $output,
93        );
94        $this->logAndOutput("Consume messages...", level: 'debug');
95        $this->symfonyUtils()->callCommand(
96            'messenger:consume',
97            new ArrayInput([
98                'receivers' => ['async'],
99                '--no-reset' => '--no-reset',
100            ]),
101            $output,
102        );
103
104        $this->logAndOutput("Ran continuously.", level: 'debug');
105        return Command::SUCCESS;
106    }
107
108    /** @param callable(): void $fn */
109    public function daily(string $time, string $ident, callable $fn): void {
110        $throttling_repo = $this->entityManager()->getRepository(Throttling::class);
111        $last_occurrence = $throttling_repo->getLastOccurrenceOf($ident);
112        $now = new \DateTime($this->dateUtils()->getIsoNow());
113        $is_too_soon = false;
114        if ($last_occurrence) {
115            // Consider daylight saving change date => not 23 hours!
116            $min_interval = \DateInterval::createFromDateString('+22 hours');
117            $min_now = $last_occurrence->add($min_interval);
118            $is_too_soon = $now < $min_now;
119        }
120        $time_diff = $this->getTimeOnlyDiffSeconds($now->format('H:i:s'), $time);
121        $is_right_time_of_day = $time_diff > 0 && $time_diff < 7200; // 2h window
122        $should_execute_now = !$is_too_soon && $is_right_time_of_day;
123        if ($should_execute_now) {
124            try {
125                $this->logAndOutput("Executing daily ({$time}{$ident}...", level: 'debug');
126                $fn();
127                $throttling_repo->recordOccurrenceOf($ident, $this->dateUtils()->getIsoNow());
128            } catch (\Throwable $th) {
129                $this->logAndOutput("Daily ({$time}{$ident} failed", level: 'error');
130            }
131        }
132    }
133
134    public function getTimeOnlyDiffSeconds(string $iso_value, string $iso_cmp): int {
135        date_default_timezone_set('Europe/Zurich');
136        $value = new \DateTime($iso_value);
137        $cmp = new \DateTime($iso_cmp);
138
139        $seconds_diff = $value->getTimestamp() - $cmp->getTimestamp();
140        $time_only_diff = $seconds_diff % 86400;
141        return match (true) {
142            $time_only_diff < -43200 => $time_only_diff + 86400,
143            $time_only_diff >= 43200 => $time_only_diff - 86400,
144            default => $time_only_diff,
145        };
146    }
147}