Files
ladill-hosting/app/Console/Commands/SyncHostingAccountUsageCommand.php
T
isaaccladandCursor e251a4cf60
Deploy Ladill Hosting / deploy (push) Failing after 17s
Initial Ladill Hosting app with Gitea deploy pipeline.
Shared web hosting extracted from the platform monolith, with CI deploy
to /var/www/ladill-hosting matching Bird/Domains/Email.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 16:24:20 +00:00

92 lines
3.6 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\HostingAccount;
use App\Models\HostingNode;
use App\Services\Hosting\NodeCapacityService;
use App\Services\Hosting\HostingResourcePolicyService;
use App\Services\Hosting\Providers\SharedNodeProvider;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
class SyncHostingAccountUsageCommand extends Command
{
protected $signature = 'hosting:sync-account-usage {--account=}';
protected $description = 'Sync per-account shared hosting usage from hosting nodes.';
private const BYTES_PER_GB = 1073741824;
public function handle(
SharedNodeProvider $sharedNodeProvider,
NodeCapacityService $capacityService,
HostingResourcePolicyService $resourcePolicyService,
): int {
$accounts = HostingAccount::query()
->with(['product', 'node', 'databases', 'user', 'latestOrder'])
->where('type', 'shared')
->whereIn('status', ['active', 'provisioning', 'suspended'])
->when($this->option('account'), fn ($query, $accountId) => $query->where('id', $accountId))
->get();
$touchedNodeIds = [];
foreach ($accounts as $account) {
if (! $account->node) {
continue;
}
try {
$usage = $sharedNodeProvider->getUsageStats($account);
$requestedDiskGb = $account->requestedDiskGb();
$account->update([
'allocated_disk_gb' => $requestedDiskGb,
'disk_used_bytes' => (int) ($usage['disk_used_bytes'] ?? $account->disk_used_bytes),
'inode_count' => (int) ($usage['inode_count'] ?? $account->inode_count),
'cpu_usage_percent' => $usage['cpu_usage_percent'] ?? $account->cpu_usage_percent,
'memory_used_mb' => (int) ($usage['memory_used_mb'] ?? $account->memory_used_mb),
'process_count' => (int) ($usage['process_count'] ?? $account->process_count),
'io_usage_mb' => $usage['io_usage_mb'] ?? $account->io_usage_mb,
'last_usage_sync_at' => now(),
]);
$resourcePolicyService->process($account->fresh(['product', 'node', 'databases', 'user', 'latestOrder']));
$touchedNodeIds[$account->hosting_node_id] = true;
$this->line(sprintf(
'%s: disk=%dGB inodes=%d cpu=%s%% mem=%dMB proc=%d',
$account->username,
(int) ceil(((int) ($usage['disk_used_bytes'] ?? 0)) / self::BYTES_PER_GB),
(int) ($usage['inode_count'] ?? 0),
$usage['cpu_usage_percent'] ?? 'n/a',
(int) ($usage['memory_used_mb'] ?? 0),
(int) ($usage['process_count'] ?? 0)
));
} catch (\Throwable $e) {
Log::warning('Failed to sync hosting account usage.', [
'hosting_account_id' => $account->id,
'username' => $account->username,
'error' => $e->getMessage(),
]);
$this->warn("Failed to sync {$account->username}: {$e->getMessage()}");
}
}
foreach (array_keys($touchedNodeIds) as $nodeId) {
$node = HostingNode::query()->find($nodeId);
if ($node) {
$capacityService->refreshNodeResourceTotals($node);
$capacityService->checkNode($node);
}
}
$this->info("Synced {$accounts->count()} hosting account(s).");
return self::SUCCESS;
}
}