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();
});