diff --git a/.idea/php.xml b/.idea/php.xml index f6b274c02..942662770 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -316,6 +316,7 @@ + diff --git a/app/Domain/Reports/Services/Reports.php b/app/Domain/Reports/Services/Reports.php index afdf9464c..ea6d7b607 100644 --- a/app/Domain/Reports/Services/Reports.php +++ b/app/Domain/Reports/Services/Reports.php @@ -8,6 +8,8 @@ use GuzzleHttp\Client; use GuzzleHttp\Promise\PromiseInterface; use Illuminate\Contracts\Container\BindingResolutionException; + use Illuminate\Support\Facades\Cache; + use Illuminate\Support\Facades\Log; use Leantime\Core\Configuration\AppSettings as AppSettingCore; use Leantime\Core\Configuration\Environment as EnvironmentCore; use Leantime\Core\Events\DispatchesEvents; @@ -90,47 +92,55 @@ public function __construct( */ public function dailyIngestion(): void { + $this->runIngestionForProject(session('currentProject')); + } + + protected function runIngestionForProject(int $projectId): void + { + + if (Cache::has('dailyReports-'.$projectId) === false || Cache::get('dailyReports-'.$projectId) < dtHelper()->dbNow()->endOfDay()) { - if ( - session()->exists('currentProject') - && - ( - ! session()->exists('reportCompleted.'.session('currentProject')) - || session('reportCompleted.'.session('currentProject')) != 1 - ) - ) { // Check if the dailyingestion cycle was executed already. There should be one entry for backlog and one entry for current sprint (unless there is no current sprint // Get current Sprint Id, if no sprint available, dont run the sprint burndown - $lastEntries = $this->reportRepository->checkLastReportEntries(session('currentProject')); + $lastEntries = $this->reportRepository->checkLastReportEntries($projectId); // If we receive 2 entries we have a report already. If we have one entry then we ran the backlog one and that means there was no current sprint. if (count($lastEntries) == 0) { - $currentSprint = $this->sprintRepository->getCurrentSprint(session('currentProject')); + $currentSprint = $this->sprintRepository->getCurrentSprint($projectId); if ($currentSprint !== false) { - $sprintReport = $this->reportRepository->runTicketReport(session('currentProject'), $currentSprint->id); + $sprintReport = $this->reportRepository->runTicketReport($projectId, $currentSprint->id); if ($sprintReport !== false) { $this->reportRepository->addReport($sprintReport); } } - $backlogReport = $this->reportRepository->runTicketReport(session('currentProject'), ''); + $backlogReport = $this->reportRepository->runTicketReport($projectId, ''); if ($backlogReport !== false) { + $this->reportRepository->addReport($backlogReport); - if (! session()->exists('reportCompleted') || is_array(session('reportCompleted')) === false) { - session(['reportCompleted' => []]); - } + Cache::put('dailyReports-'.$projectId, dtHelper()->dbNow()->endOfDay(), 14400); // 4hours - session(['reportCompleted.'.session('currentProject') => 1]); } } + } } + public function cronDailyIngestion(): void + { + $projects = $this->projectRepository->getAll(); + + foreach ($projects as $project) { + $this->runIngestionForProject($project['id']); + } + + } + /** * @api */ @@ -261,7 +271,7 @@ public function getAnonymousTelemetry( 'serverSoftware' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown', 'phpUname' => php_uname(), - 'isDocker' => is_file('/.dockerenv'), + 'isDocker' => $this->isRunningInDocker(), 'phpSapiName' => php_sapi_name(), 'phpOs' => PHP_OS ?? 'unknown', @@ -312,7 +322,7 @@ public function sendAnonymousTelemetry(): bool|PromiseInterface return $promise; } catch (\Exception $e) { - report($e); + Log::error($e); return false; } @@ -473,6 +483,34 @@ public function generateTicketReactionsReport() return $reactions; } + + /** + * Checks if Leantime is running in a Docker environment + * Uses multiple detection methods and handles errors gracefully + */ + private function isRunningInDocker(): bool + { + // Method 1: Check for /.dockerenv file + try { + if (is_file('/.dockerenv')) { + return true; + } + } catch (\Exception $e) { + // Silently fail if file access is restricted + } + + // Method 2: Check for Docker-specific environment variables + if (getenv('DOCKER_CONTAINER') !== false || getenv('IS_DOCKER') !== false) { + return true; + } + + // Method 3: Check cgroup info (works on Linux hosts) + try { + return strpos(file_get_contents('/proc/1/cgroup'), 'docker') !== false; + } catch (\Exception $e) { + return false; // Return false if all detection methods fail + } + } } } diff --git a/app/Domain/Reports/register.php b/app/Domain/Reports/register.php index 538d440b1..d78d35ac3 100644 --- a/app/Domain/Reports/register.php +++ b/app/Domain/Reports/register.php @@ -34,5 +34,5 @@ })->name('reports:telemetry')->everyMinute(); - $scheduler->call(fn () => $reportService->dailyIngestion())->name('reports:dailyIngestion')->everyMinute(); + $scheduler->call(fn () => $reportService->cronDailyIngestion())->name('reports:dailyIngestion')->everyMinute(); });