| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- <?php
- namespace App\Module\ThirdParty\Commands;
- use Illuminate\Console\Command;
- use App\Module\ThirdParty\Models\ThirdPartyQuota;
- use App\Module\ThirdParty\Enums\QUOTA_TYPE;
- /**
- * 第三方服务配额重置命令
- */
- class QuotaResetCommand extends Command
- {
- /**
- * 命令签名
- *
- * @var string
- */
- protected $signature = 'thirdparty:quota-reset
- {--service= : 指定服务ID}
- {--type= : 指定配额类型}
- {--force : 强制重置所有配额}
- {--dry-run : 只显示将要重置的配额,不实际执行}';
- /**
- * 命令描述
- *
- * @var string
- */
- protected $description = '重置第三方服务配额';
- /**
- * 执行命令
- *
- * @return int
- */
- public function handle(): int
- {
- $this->info('开始检查和重置第三方服务配额...');
- try {
- $quotas = $this->getQuotasToReset();
-
- if ($quotas->isEmpty()) {
- $this->info('没有找到需要重置的配额');
- return Command::SUCCESS;
- }
- $this->displayQuotasToReset($quotas);
- if ($this->option('dry-run')) {
- $this->info('这是预览模式,没有实际重置配额');
- return Command::SUCCESS;
- }
- if (!$this->option('force') && !$this->confirm('确认要重置这些配额吗?')) {
- $this->info('操作已取消');
- return Command::SUCCESS;
- }
- $resetCount = $this->resetQuotas($quotas);
-
- $this->info("成功重置了 {$resetCount} 个配额");
- return Command::SUCCESS;
- } catch (\Exception $e) {
- $this->error("配额重置失败: {$e->getMessage()}");
- return Command::FAILURE;
- }
- }
- /**
- * 获取需要重置的配额
- *
- * @return \Illuminate\Database\Eloquent\Collection
- */
- protected function getQuotasToReset()
- {
- $query = ThirdPartyQuota::with('service')->where('is_active', true);
- // 按服务过滤
- if ($serviceId = $this->option('service')) {
- $query->where('service_id', $serviceId);
- }
- // 按类型过滤
- if ($type = $this->option('type')) {
- if (!QUOTA_TYPE::tryFrom($type)) {
- throw new \Exception("无效的配额类型: {$type}");
- }
- $query->where('type', $type);
- }
- // 如果强制重置,返回所有匹配的配额
- if ($this->option('force')) {
- return $query->get();
- }
- // 否则只返回需要重置的配额
- return $query->get()->filter(function ($quota) {
- return $quota->needsReset();
- });
- }
- /**
- * 显示将要重置的配额
- *
- * @param \Illuminate\Database\Eloquent\Collection $quotas
- * @return void
- */
- protected function displayQuotasToReset($quotas): void
- {
- $this->info("\n将要重置的配额:");
- $this->line(str_repeat('-', 100));
- $headers = ['服务', '配额类型', '限制值', '已使用', '使用率', '状态', '重置原因'];
- $rows = [];
- foreach ($quotas as $quota) {
- $usagePercentage = round($quota->getUsagePercentage(), 2) . '%';
- $status = $quota->getStatusLabel();
-
- $reason = '';
- if ($this->option('force')) {
- $reason = '强制重置';
- } elseif ($quota->needsReset()) {
- if ($quota->window_end && now()->gt($quota->window_end)) {
- $reason = '时间窗口已过期';
- } elseif ($quota->reset_at && now()->gte($quota->reset_at)) {
- $reason = '到达重置时间';
- } else {
- $reason = '需要重置';
- }
- }
- $rows[] = [
- $quota->service->name,
- $quota->getTypeLabel(),
- number_format($quota->limit_value),
- number_format($quota->used_value),
- $usagePercentage,
- $status,
- $reason,
- ];
- }
- $this->table($headers, $rows);
- }
- /**
- * 重置配额
- *
- * @param \Illuminate\Database\Eloquent\Collection $quotas
- * @return int
- */
- protected function resetQuotas($quotas): int
- {
- $resetCount = 0;
- $progressBar = $this->output->createProgressBar($quotas->count());
- $progressBar->start();
- foreach ($quotas as $quota) {
- try {
- $quota->resetQuota();
- $resetCount++;
-
- $this->line("\n重置配额: {$quota->service->name} - {$quota->getTypeLabel()}");
-
- } catch (\Exception $e) {
- $this->line("\n<fg=red>重置失败: {$quota->service->name} - {$quota->getTypeLabel()}: {$e->getMessage()}</fg>");
- }
-
- $progressBar->advance();
- }
- $progressBar->finish();
- $this->line('');
- return $resetCount;
- }
- /**
- * 显示配额统计信息
- *
- * @return void
- */
- protected function displayQuotaStats(): void
- {
- $totalQuotas = ThirdPartyQuota::where('is_active', true)->count();
- $exceededQuotas = ThirdPartyQuota::where('is_active', true)
- ->where('is_exceeded', true)
- ->count();
- $nearThresholdQuotas = ThirdPartyQuota::where('is_active', true)
- ->whereRaw('(used_value / limit_value * 100) >= alert_threshold')
- ->count();
- $this->info("\n配额统计:");
- $this->line("总配额数: {$totalQuotas}");
- $this->line("已超限配额: {$exceededQuotas}");
- $this->line("接近阈值配额: {$nearThresholdQuotas}");
- if ($exceededQuotas > 0) {
- $this->warn("\n警告: 有 {$exceededQuotas} 个配额已超限,可能影响服务调用");
- }
- }
- /**
- * 验证配额类型
- *
- * @param string $type
- * @return bool
- */
- protected function validateQuotaType(string $type): bool
- {
- return QUOTA_TYPE::tryFrom($type) !== null;
- }
- /**
- * 获取所有可用的配额类型
- *
- * @return array
- */
- protected function getAvailableQuotaTypes(): array
- {
- return array_map(fn($case) => $case->value, QUOTA_TYPE::cases());
- }
- }
|