diff --git a/app/config/collections.php b/app/config/collections.php index 438a825c95..7c947cb086 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -2183,22 +2183,22 @@ $collections = [ 'name' => 'Builds', 'attributes' => [ [ - '$id' => 'startTime', // todo: change to datetime - 'type' => Database::VAR_INTEGER, + '$id' => 'startTime', // todo: change to datetime in motion + 'type' => Database::VAR_DATETIME, 'format' => '', 'size' => 0, - 'signed' => true, + 'signed' => false, 'required' => false, 'default' => null, 'array' => false, 'filters' => [], ], [ - '$id' => 'endTime', // todo: change to datetime - 'type' => Database::VAR_INTEGER, + '$id' => 'endTime', // todo: change to datetime in motion + 'type' => Database::VAR_DATETIME, 'format' => '', 'size' => 0, - 'signed' => true, + 'signed' => false, 'required' => false, 'default' => null, 'array' => false, @@ -2398,7 +2398,7 @@ $collections = [ 'filters' => [], ], [ - '$id' => 'time', // todo: change to datetime??? + '$id' => 'time', 'type' => Database::VAR_FLOAT, 'format' => '', 'size' => 0, @@ -2658,11 +2658,11 @@ $collections = [ ], [ '$id' => 'time', - 'type' => Database::VAR_INTEGER, // todo: change to datetime + 'type' => Database::VAR_DATETIME,// todo: change to datetime in motion 'format' => '', 'size' => 0, 'signed' => false, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2699,16 +2699,16 @@ $collections = [ 'orders' => [Database::ORDER_DESC], ], [ - '$id' => '_key_metric', + '$id' => '_key_period_time', 'type' => Database::INDEX_KEY, - 'attributes' => ['metric'], + 'attributes' => ['period', 'time'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ - '$id' => '_key_metric_period', + '$id' => '_key_metric_period_time', 'type' => Database::INDEX_KEY, - 'attributes' => ['metric', 'period'], + 'attributes' => ['metric', 'period', 'time'], 'lengths' => [], 'orders' => [Database::ORDER_DESC], ], diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 1ada1e8e1c..7c1b77e4b7 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2529,11 +2529,11 @@ App::get('/v1/databases/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } - // TODO@kodumbeats explore performance if query is ordered by time ASC + // Added 3'rd level to Index [period, metric, time] because of order by. $stats[$metric] = array_reverse($stats[$metric]); } }); @@ -2641,7 +2641,7 @@ App::get('/v1/databases/:databaseId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } @@ -2754,7 +2754,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 435258c84a..0077f311e2 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -256,7 +256,7 @@ App::get('/v1/functions/:functionId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index f890e61cbe..8200cca2a3 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -314,7 +314,7 @@ App::get('/v1/projects/:projectId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 554d739ec5..41f04992a6 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1547,7 +1547,7 @@ App::get('/v1/storage/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } @@ -1656,7 +1656,7 @@ App::get('/v1/storage/:bucketId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index df6d279be3..9ada18396e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -925,7 +925,7 @@ App::get('/v1/users/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period + 'date' => Database::dateAddSeconds(new DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), ]; $backfill--; } diff --git a/app/executor.php b/app/executor.php index 7bf42c98db..891995871e 100644 --- a/app/executor.php +++ b/app/executor.php @@ -12,6 +12,7 @@ use Swoole\Runtime; use Swoole\Timer; use Utopia\App; use Utopia\CLI\Console; +use Utopia\Database\Database; use Utopia\Logger\Log; use Utopia\Logger\Logger; use Utopia\Orchestration\Adapter\DockerCLI; @@ -188,8 +189,9 @@ App::post('/v1/runtimes') $containerId = ''; $stdout = ''; $stderr = ''; - $startTime = \time(); - $endTime = 0; + $startTime = Database::getCurrentDateTime(); + $startTimeUnix = (new DateTime($startTime))->getTimestamp(); + $endTimeUnix = 0; $orchestration = $orchestrationPool->get(); $secret = \bin2hex(\random_bytes(16)); @@ -198,8 +200,8 @@ App::post('/v1/runtimes') $activeRuntimes->set($runtimeId, [ 'id' => $containerId, 'name' => $runtimeId, - 'created' => $startTime, - 'updated' => $endTime, + 'created' => $startTimeUnix, + 'updated' => $endTimeUnix, 'status' => 'pending', 'key' => $secret, ]); @@ -262,7 +264,7 @@ App::post('/v1/runtimes') labels: [ 'openruntimes-id' => $runtimeId, 'openruntimes-type' => 'runtime', - 'openruntimes-created' => strval($startTime), + 'openruntimes-created' => strval($startTimeUnix), 'openruntimes-runtime' => $runtime, ], workdir: $workdir, @@ -319,28 +321,32 @@ App::post('/v1/runtimes') $stdout = 'Build Successful!'; } - $endTime = \time(); + $endTime = Database::getCurrentDateTime(); + $endTimeUnix = (new DateTime($endTime))->getTimestamp(); + $duration = $endTimeUnix - $startTimeUnix; + $container = array_merge($container, [ 'status' => 'ready', 'response' => \mb_strcut($stdout, 0, 1000000), // Limit to 1MB 'stderr' => \mb_strcut($stderr, 0, 1000000), // Limit to 1MB 'startTime' => $startTime, 'endTime' => $endTime, - 'duration' => $endTime - $startTime, + 'duration' => $duration, ]); + if (!$remove) { $activeRuntimes->set($runtimeId, [ 'id' => $containerId, 'name' => $runtimeId, - 'created' => $startTime, - 'updated' => $endTime, - 'status' => 'Up ' . \round($endTime - $startTime, 2) . 's', + 'created' => $startTimeUnix, + 'updated' => $endTimeUnix, + 'status' => 'Up ' . \round($duration, 2) . 's', 'key' => $secret, ]); } - Console::success('Build Stage completed in ' . ($endTime - $startTime) . ' seconds'); + Console::success('Build Stage completed in ' . ($duration) . ' seconds'); } catch (Throwable $th) { Console::error('Build failed: ' . $th->getMessage() . $stdout); diff --git a/app/tasks/maintenance.php b/app/tasks/maintenance.php index eb50dbc0e2..ecd7197a63 100644 --- a/app/tasks/maintenance.php +++ b/app/tasks/maintenance.php @@ -57,7 +57,7 @@ $cli { (new Delete()) ->setType(DELETE_TYPE_EXECUTIONS) - ->setTimestamp(time() - $interval) + ->setDatetime(Database::dateAddSeconds(new DateTime(), -1 * $interval)) ->trigger(); } @@ -65,7 +65,7 @@ $cli { (new Delete()) ->setType(DELETE_TYPE_ABUSE) - ->setTimestamp(time() - $interval) + ->setDatetime(Database::dateAddSeconds(new DateTime(), -1 * $interval)) ->trigger(); } @@ -73,7 +73,7 @@ $cli { (new Delete()) ->setType(DELETE_TYPE_AUDIT) - ->setTimestamp(time() - $interval) + ->setDatetime(Database::dateAddSeconds(new DateTime(), -1 * $interval)) ->trigger(); } @@ -81,8 +81,8 @@ $cli { (new Delete()) ->setType(DELETE_TYPE_USAGE) - ->setTimestamp1d(time() - $interval1d) - ->setTimestamp30m(time() - $interval30m) + ->setDateTime1d(Database::dateAddSeconds(new DateTime(), -1 * $interval1d)) + ->setDateTime30m(Database::dateAddSeconds(new DateTime(), -1 * $interval30m)) ->trigger(); } @@ -90,7 +90,7 @@ $cli { (new Delete()) ->setType(DELETE_TYPE_REALTIME) - ->setTimestamp(time() - 60) + ->setDatetime(Database::dateAddSeconds(new DateTime(), -60)) ->trigger(); } @@ -98,16 +98,17 @@ $cli { (new Delete()) ->setType(DELETE_TYPE_SESSIONS) - ->setTimestamp(time() - Auth::TOKEN_EXPIRATION_LOGIN_LONG) + ->setDatetime(Database::dateAddSeconds(new DateTime(), -1 * Auth::TOKEN_EXPIRATION_LOGIN_LONG)) ->trigger(); } function renewCertificates($dbForConsole) { - $time = date('d-m-Y H:i:s', time()); + $time = Database::getCurrentDateTime(); + $certificates = $dbForConsole->find('certificates', [ new Query('attempts', Query::TYPE_LESSEREQUAL, [5]), // Maximum 5 attempts - new Query('renewDate', Query::TYPE_LESSEREQUAL, [\time()]) // includes 60 days cooldown (we have 30 days to renew) + new Query('renewDate', Query::TYPE_LESSEREQUAL, [$time]) // includes 60 days cooldown (we have 30 days to renew) ], 200); // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains) @@ -138,7 +139,8 @@ $cli Console::loop(function () use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d) { $database = getConsoleDB(); - $time = date('d-m-Y H:i:s', time()); + $time = Database::getCurrentDateTime(); + Console::info("[{$time}] Notifying workers with maintenance tasks every {$interval} seconds"); notifyDeleteExecutionLogs($executionLogsRetention); notifyDeleteAbuseLogs($abuseLogsRetention); diff --git a/app/workers/builds.php b/app/workers/builds.php index 7bca269128..19d9f35eab 100644 --- a/app/workers/builds.php +++ b/app/workers/builds.php @@ -7,7 +7,6 @@ use Appwrite\Utopia\Response\Model\Deployment; use Cron\CronExpression; use Executor\Executor; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\App; use Utopia\CLI\Console; use Utopia\Storage\Storage; @@ -76,8 +75,7 @@ class BuildsV1 extends Worker } $buildId = $deployment->getAttribute('buildId', ''); - $build = null; - $startTime = \time(); + $startTime = Database::getCurrentDateTime(); if (empty($buildId)) { $buildId = $dbForProject->getId(); $build = $dbForProject->createDocument('builds', new Document([ @@ -93,7 +91,7 @@ class BuildsV1 extends Worker 'sourceType' => App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL), 'stdout' => '', 'stderr' => '', - 'endTime' => 0, + 'endTime' => null, 'duration' => 0 ])); $deployment->setAttribute('buildId', $buildId); @@ -167,6 +165,9 @@ class BuildsV1 extends Worker ); /** Update the build document */ + + //$response['endTime'] = Database::dateFormat((new DateTime())->setTimestamp($response['endTime'])); //todo: fix to datetime + $build->setAttribute('endTime', $response['endTime']); $build->setAttribute('duration', $response['duration']); $build->setAttribute('status', $response['status']); @@ -189,9 +190,10 @@ class BuildsV1 extends Worker $function->setAttribute('scheduleNext', $next); $function = $dbForProject->updateDocument('functions', $function->getId(), $function); } catch (\Throwable $th) { - $endtime = \time(); + $endtime = Database::getCurrentDateTime(); + $interval = (new DateTime($endtime))->diff(new DateTime($startTime)); $build->setAttribute('endTime', $endtime); - $build->setAttribute('duration', $endtime - $startTime); + $build->setAttribute('duration', $interval->format('%s')); $build->setAttribute('status', 'failed'); $build->setAttribute('stderr', $th->getMessage()); Console::error($th->getMessage()); diff --git a/app/workers/deletes.php b/app/workers/deletes.php index ed818f8356..d605e7b444 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -4,7 +4,6 @@ use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Appwrite\Resque\Worker; use Executor\Executor; use Utopia\Storage\Device\Local; @@ -75,17 +74,17 @@ class DeletesV1 extends Worker break; case DELETE_TYPE_EXECUTIONS: - $this->deleteExecutionLogs($this->args['timestamp']); + $this->deleteExecutionLogs($this->args['datetime']); break; case DELETE_TYPE_AUDIT: - $timestamp = $this->args['timestamp'] ?? 0; - $document = new Document($this->args['document'] ?? []); - - if (!empty($timestamp)) { - $this->deleteAuditLogs($this->args['timestamp']); + $datetime = $this->args['datetime'] ?? null; + if (!empty($datetime)) { + $this->deleteAuditLogs($datetime); } + $document = new Document($this->args['document'] ?? []); + if (!$document->isEmpty()) { $this->deleteAuditLogsByResource('document/' . $document->getId(), $project->getId()); } @@ -93,15 +92,15 @@ class DeletesV1 extends Worker break; case DELETE_TYPE_ABUSE: - $this->deleteAbuseLogs($this->args['timestamp']); + $this->deleteAbuseLogs($this->args['datetime']); break; case DELETE_TYPE_REALTIME: - $this->deleteRealtimeUsage($this->args['timestamp']); + $this->deleteRealtimeUsage($this->args['datetime']); break; case DELETE_TYPE_SESSIONS: - $this->deleteExpiredSessions($this->args['timestamp']); + $this->deleteExpiredSessions($this->args['datetime']); break; case DELETE_TYPE_CERTIFICATES: @@ -110,7 +109,7 @@ class DeletesV1 extends Worker break; case DELETE_TYPE_USAGE: - $this->deleteUsageStats($this->args['timestamp1d'], $this->args['timestamp30m']); + $this->deleteUsageStats($this->args['dateTime1d'], $this->args['dateTime30m']); break; default: Console::error('No delete operation for type: ' . $type); @@ -166,21 +165,21 @@ class DeletesV1 extends Worker } /** - * @param int $timestamp1d - * @param int $timestamp30m + * @param string $datetime1d + * @param string $datetime30m */ - protected function deleteUsageStats(int $timestamp1d, int $timestamp30m) + protected function deleteUsageStats(string $datetime1d, string $datetime30m) { - $this->deleteForProjectIds(function (string $projectId) use ($timestamp1d, $timestamp30m) { + $this->deleteForProjectIds(function (string $projectId) use ($datetime1d, $datetime30m) { $dbForProject = $this->getProjectDB($projectId); // Delete Usage stats $this->deleteByGroup('stats', [ - new Query('time', Query::TYPE_LESSER, [$timestamp1d]), + new Query('time', Query::TYPE_LESSER, [$datetime1d]), new Query('period', Query::TYPE_EQUAL, ['1d']), ], $dbForProject); $this->deleteByGroup('stats', [ - new Query('time', Query::TYPE_LESSER, [$timestamp30m]), + new Query('time', Query::TYPE_LESSER, [$datetime30m]), new Query('period', Query::TYPE_EQUAL, ['30m']), ], $dbForProject); }); @@ -261,61 +260,62 @@ class DeletesV1 extends Worker } /** - * @param int $timestamp + * @param string $datetime */ - protected function deleteExecutionLogs(int $timestamp): void + protected function deleteExecutionLogs(string $datetime): void { - $this->deleteForProjectIds(function (string $projectId) use ($timestamp) { + $this->deleteForProjectIds(function (string $projectId) use ($datetime) { $dbForProject = $this->getProjectDB($projectId); // Delete Executions $this->deleteByGroup('executions', [ - new Query('$createdAt', Query::TYPE_LESSER, [$timestamp]) + new Query('$createdAt', Query::TYPE_LESSER, [$datetime]) ], $dbForProject); }); } /** - * @param int $timestamp + * @param string $datetime */ - protected function deleteExpiredSessions(int $timestamp): void + protected function deleteExpiredSessions(string $datetime): void { - $this->deleteForProjectIds(function (string $projectId) use ($timestamp) { + $this->deleteForProjectIds(function (string $projectId) use ($datetime) { $dbForProject = $this->getProjectDB($projectId); // Delete Sessions $this->deleteByGroup('sessions', [ - new Query('expire', Query::TYPE_LESSER, [$timestamp]) + new Query('expire', Query::TYPE_LESSER, [$datetime]) ], $dbForProject); }); } /** - * @param int $timestamp + * @param string $datetime */ - protected function deleteRealtimeUsage(int $timestamp): void + protected function deleteRealtimeUsage(string $datetime): void { - $this->deleteForProjectIds(function (string $projectId) use ($timestamp) { + $this->deleteForProjectIds(function (string $projectId) use ($datetime) { $dbForProject = $this->getProjectDB($projectId); // Delete Dead Realtime Logs $this->deleteByGroup('realtime', [ - new Query('timestamp', Query::TYPE_LESSER, [$timestamp]) + new Query('timestamp', Query::TYPE_LESSER, [$datetime]) ], $dbForProject); }); } /** - * @param int $timestamp + * @param string $datetime + * @throws Exception */ - protected function deleteAbuseLogs(int $timestamp): void + protected function deleteAbuseLogs(string $datetime): void { - if ($timestamp == 0) { - throw new Exception('Failed to delete audit logs. No timestamp provided'); + if (empty($datetime)) { + throw new Exception('Failed to delete audit logs. No datetime provided'); } - $this->deleteForProjectIds(function (string $projectId) use ($timestamp) { + $this->deleteForProjectIds(function (string $projectId) use ($datetime) { $dbForProject = $this->getProjectDB($projectId); $timeLimit = new TimeLimit("", 0, 1, $dbForProject); $abuse = new Abuse($timeLimit); - + $timestamp = (new DateTime($datetime))->getTimestamp(); //todo:make abuse get datetime $status = $abuse->cleanup($timestamp); if (!$status) { throw new Exception('Failed to delete Abuse logs for project ' . $projectId); @@ -324,16 +324,19 @@ class DeletesV1 extends Worker } /** - * @param int $timestamp + * @param string $datetime + * @throws Exception */ - protected function deleteAuditLogs(int $timestamp): void + protected function deleteAuditLogs(string $datetime): void { - if ($timestamp == 0) { - throw new Exception('Failed to delete audit logs. No timestamp provided'); + if (empty($datetime)) { + throw new Exception('Failed to delete audit logs. No datetime provided'); } - $this->deleteForProjectIds(function (string $projectId) use ($timestamp) { + + $this->deleteForProjectIds(function (string $projectId) use ($datetime) { $dbForProject = $this->getProjectDB($projectId); $audit = new Audit($dbForProject); + $timestamp = (new DateTime($datetime))->getTimestamp(); //todo:make audit get datetime $status = $audit->cleanup($timestamp); if (!$status) { throw new Exception('Failed to delete Audit logs for project' . $projectId); @@ -342,7 +345,8 @@ class DeletesV1 extends Worker } /** - * @param int $timestamp + * @param string $resource + * @param string $projectId */ protected function deleteAuditLogsByResource(string $resource, string $projectId): void { diff --git a/src/Appwrite/Event/Delete.php b/src/Appwrite/Event/Delete.php index 057abe17f7..0bfbfb12a9 100644 --- a/src/Appwrite/Event/Delete.php +++ b/src/Appwrite/Event/Delete.php @@ -8,10 +8,10 @@ use Utopia\Database\Document; class Delete extends Event { protected string $type = ''; - protected ?int $timestamp = null; - protected ?int $timestamp1d = null; - protected ?int $timestamp30m = null; protected ?Document $document = null; + protected ?string $datetime = null; + protected ?string $datetime1d = null; + protected ?string $datetime30m = null; public function __construct() { @@ -42,41 +42,38 @@ class Delete extends Event } /** - * Set timestamp. + * set Datetime. * - * @param int $timestamp + * @param string $datetime * @return self */ - public function setTimestamp(int $timestamp): self + public function setDatetime(string $datetime): self { - $this->timestamp = $timestamp; - + $this->datetime = $datetime; return $this; } /** - * Set timestamp for 1 day interval. + * Set datetime for 1 day interval. * - * @param int $timestamp + * @param string $datetime * @return self */ - public function setTimestamp1d(int $timestamp): self + public function setDatetime1d(string $datetime): self { - $this->timestamp1d = $timestamp; - + $this->datetime1d = $datetime; return $this; } /** - * Sets timestamp for 30m interval. + * Sets datetime for 30m interval. * - * @param int $timestamp + * @param string $datetime * @return self */ - public function setTimestamp30m(int $timestamp): self + public function setDatetime30m(string $datetime): self { - $this->timestamp30m = $timestamp; - + $this->datetime30m = $datetime; return $this; } @@ -115,9 +112,9 @@ class Delete extends Event 'project' => $this->project, 'type' => $this->type, 'document' => $this->document, - 'timestamp' => $this->timestamp, - 'timestamp1d' => $this->timestamp1d, - 'timestamp30m' => $this->timestamp30m + 'datetime' => $this->datetime, + 'datetime1d' => $this->datetime1d, + 'datetime30m' => $this->datetime30m ]); } } diff --git a/src/Appwrite/Stats/Usage.php b/src/Appwrite/Stats/Usage.php index 341e6c19e8..2e0b283f18 100644 --- a/src/Appwrite/Stats/Usage.php +++ b/src/Appwrite/Stats/Usage.php @@ -191,12 +191,12 @@ class Usage protected array $periods = [ [ 'key' => '30m', - 'multiplier' => 1800, + //'multiplier' => 1800, 'startTime' => '-24 hours', ], [ 'key' => '1d', - 'multiplier' => 86400, + //'multiplier' => 86400, 'startTime' => '-90 days', ], ]; @@ -213,7 +213,7 @@ class Usage * Create or update each metric in the stats collection for the given project * * @param string $projectId - * @param int $time + * @param string $time * @param string $period * @param string $metric * @param int $value @@ -221,7 +221,7 @@ class Usage * * @return void */ - private function createOrUpdateMetric(string $projectId, int $time, string $period, string $metric, int $value, int $type): void + private function createOrUpdateMetric(string $projectId, string $time, string $period, string $metric, int $value, int $type): void { $id = \md5("{$time}_{$period}_{$metric}"); $this->database->setNamespace('_console'); @@ -246,7 +246,10 @@ class Usage $document->setAttribute('value', $value) ); } + + $time = (new DateTime($time))->getTimestamp(); //todo: What about this timestamp? $this->latestTime[$metric][$period] = $time; + } catch (\Exception $e) { // if projects are deleted this might fail if (is_callable($this->errorHandler)) { call_user_func($this->errorHandler, $e, "sync_project_{$projectId}_metric_{$metric}"); @@ -311,7 +314,8 @@ class Usage } } - $time = \strtotime($point['time']); + //$time = \strtotime($point['time']); + $time = $point['time']; //todo: check is this datetime format? $value = (!empty($point['value'])) ? $point['value'] : 0; $this->createOrUpdateMetric( diff --git a/src/Appwrite/Stats/UsageDB.php b/src/Appwrite/Stats/UsageDB.php index 44f9e92bb0..e159295792 100644 --- a/src/Appwrite/Stats/UsageDB.php +++ b/src/Appwrite/Stats/UsageDB.php @@ -2,6 +2,7 @@ namespace Appwrite\Stats; +use Exception; use Utopia\Database\Database; use Utopia\Database\Document; @@ -12,6 +13,7 @@ class UsageDB extends Usage $this->database = $database; $this->errorHandler = $errorHandler; } + /** * Create or Update Mertic * Create or update each metric in the stats collection for the given project @@ -21,12 +23,22 @@ class UsageDB extends Usage * @param int $value * * @return void + * @throws Exception */ private function createOrUpdateMetric(string $projectId, string $metric, int $value): void { foreach ($this->periods as $options) { $period = $options['key']; - $time = (int) (floor(time() / $options['multiplier']) * $options['multiplier']); + $date = new \DateTime(); + if ($period === '30m') { + $minutes = $date->format('i') >= '30' ? "30" : "00"; + $time = $date->format('Y-m-d H:' . $minutes . ':00'); + } elseif ($period === '1d') { + $time = $date->format('Y-m-d 00:00:00'); + } else { + throw new Exception("Period type not found", 500); + } + $id = \md5("{$time}_{$period}_{$metric}"); $this->database->setNamespace('_' . $projectId); @@ -48,7 +60,7 @@ class UsageDB extends Usage $document->setAttribute('value', $value) ); } - } catch (\Exception$e) { // if projects are deleted this might fail + } catch (Exception$e) { // if projects are deleted this might fail if (is_callable($this->errorHandler)) { call_user_func($this->errorHandler, $e, "sync_project_{$projectId}_metric_{$metric}"); } else { @@ -80,7 +92,7 @@ class UsageDB extends Usage while ($sum === $limit) { try { $results = $this->database->find($collection, $queries, $limit, cursor:$latestDocument); - } catch (\Exception $e) { + } catch (Exception $e) { if (is_callable($this->errorHandler)) { call_user_func($this->errorHandler, $e, "fetch_documents_project_{$projectId}_collection_{$collection}"); return; @@ -113,6 +125,7 @@ class UsageDB extends Usage * @param string $metric * * @return int + * @throws Exception */ private function sum(string $projectId, string $collection, string $attribute, string $metric): int { @@ -122,7 +135,7 @@ class UsageDB extends Usage $sum = (int) $this->database->sum($collection, $attribute); $this->createOrUpdateMetric($projectId, $metric, $sum); return $sum; - } catch (\Exception $e) { + } catch (Exception $e) { if (is_callable($this->errorHandler)) { call_user_func($this->errorHandler, $e, "fetch_sum_project_{$projectId}_collection_{$collection}"); } else { @@ -140,6 +153,7 @@ class UsageDB extends Usage * @param string $metric * * @return int + * @throws Exception */ private function count(string $projectId, string $collection, string $metric): int { @@ -149,7 +163,7 @@ class UsageDB extends Usage $count = $this->database->count($collection); $this->createOrUpdateMetric($projectId, $metric, $count); return $count; - } catch (\Exception $e) { + } catch (Exception $e) { if (is_callable($this->errorHandler)) { call_user_func($this->errorHandler, $e, "fetch_count_project_{$projectId}_collection_{$collection}"); } else { diff --git a/src/Appwrite/Utopia/Response/Model/Build.php b/src/Appwrite/Utopia/Response/Model/Build.php index a09ccafa5e..b95ee9dc72 100644 --- a/src/Appwrite/Utopia/Response/Model/Build.php +++ b/src/Appwrite/Utopia/Response/Model/Build.php @@ -16,12 +16,6 @@ class Build extends Model 'default' => '', 'example' => '5e5ea5c16897e', ]) - ->addRule('startTime', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'The deployment creation date in Unix timestamp.', - 'default' => 0, - 'example' => 1592981250, - ]) ->addRule('deploymentId', [ 'type' => self::TYPE_STRING, 'description' => 'The deployment that created this build.', @@ -51,11 +45,17 @@ class Build extends Model 'default' => '', 'example' => '', ]) + ->addRule('startTime', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'The deployment creation date in Datetime.', + 'default' => '', + 'example' => '1975-12-06 13:30:59', + ]) ->addRule('endTime', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'The time the build was finished in Unix timestamp.', - 'default' => 0, - 'example' => 0, + 'type' => self::TYPE_DATETIME, + 'description' => 'The time the build was finished in Datetime.', + 'default' => '', + 'example' => '1975-12-06 13:30:59', ]) ->addRule('duration', [ 'type' => self::TYPE_INTEGER,